抽象工厂模式详解 —— head first 设计模式

设计模式文章

中介者模式

代理模式

抽象工厂模式详解 —— head first 设计模式

装饰者模式

适配器模式

策略模式

观察者模式

建造者模式 (Builder)

项目实例

假设你有一家 pizza 店,你有很多种 pizza,要在系统中显示你所有 pizza 种类。实现这个功能并不难,使用普通方式实现:

public class PizzaStore {
     Pizza orderPizza(String type) {
       Pizza pizza = null;
       if (type.equals("cheese")) {
         pizza = new CheesePizza();
       } else if (type.equals("clam")) {
           pizza =  ClamPizza();
       } if (type.equals("veggie" VeggiePizza();
       }
     pizza.prepare();
     pizza.bake();
     pizza.cut();
     pizza.box();
     return pizza;
   }
}

这种把选择披萨和制作过程全放在一起,如果新推出一款披萨就要修改 OrderPizza 方法,不符合开闭原则。

我们可已经这段变化的代码移到一个专门的类中,这个类只管创建 Pizza,我们将这个类的对象称之为“工厂”;

简单工厂(factory)

根据“将变化抽离并封装“的原则,我们可以将创建 pizza 实例这一块给抽离出来,因为这块后边可能会新增一些别的 pizza 类型,由一个对象来专职创建 pizza 对象。如果有一个 SimplePizzaFactory,那么 orderPizza() 就变成此对象的客户;

当客户下单,pizzaStore 调用 orderPizza() 的时候,就叫比萨工厂做一个,orderPizza() 只关心从工厂得到一个比萨;

 SimplePizzaFactory {
        public PizzaCreatePizza(string pizzaType){
            Pizza pizza = ;
            if(pizzaType.Equals("cheese"))
                pizza = newCheesePizza();
            if (pizzaType.Equals("pepperoni" newPepperoniPizza();
            if(pizzaType.Equals("clam" newCalmPizza();
            if(pizzaType.Equals("veggie" newVeggiePizza();
             pizza;
        }
    }

接下来看下 Pizza 类:

 Pizza {
        Pizza OrderPizza(stringpizzaType){
            Pizza pizza;
            SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();//生成pizza
            pizza =simplePizzaFactory.CreatePizza(pizzaType);
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
             pizza;
        }
}

这样的话,就可以遵循了把变化的部分抽象成一个类。下次需要变化,只需要对变化的类的部分做修改即可。

下面给出其UML图。

image

简单工厂的目的,主要负责实现生产对象的细节,根据订单来生产。每一个商店有对应着自己的工厂。在此,可以将 OrderPizza 是工厂的一个客户,当然还可以是其他类似的方法,比如 PizzaShopMenu 也可以是工厂的客户。客户就是为了获取工厂生成的对象。前者是为了卖给 people,后者是为了使用 Pizza 类获取其描述和价格等。这样遵循了找出变化的部分,将其封装到一个类中的原则,从而到达了复用的目的。

简单工厂之所以简单是因为它只根据需要,来生产出来指定的 Pizza。

特点:所有的产品都由一个工厂来生产。

上面的简单工厂并不是一个真正的模式,只是一种编程习惯,这个不能算工厂模式,不过也算是基本满足需求。

接下来我们来看看工厂方法的实现。

工厂方法

背景更新:

假如现在你要开分店,各种加盟商进来后,他们都要开发符合本地口味的 pizza,那就需要各个地方都有一个工厂,也就是每个地方继承 SimpleFactory类,但是每个工厂并不是完全使用你原来的烘培方法。或许,我们可以像 1 中那样利用简单的工厂,对应不同地区的加盟店创建不同的工厂。

这样做导致的另一个问题就是,不同的加盟店披萨的制作流程、方法可能不同,如何才能把加盟店和创建披萨捆绑在一起的同时又保持一定的弹性?

我们可以把 CreatePizza()方法放回到 PizzaStore 中,但是要把它设置为抽象方法,然后为每一个区域加盟店创建一个 PizzaStore 的子类。

如下所示:

 

 

 对应的代码如下:

abstract  PizzaStore  {
         PizzaOrderPizza(string pizzaType) {
            Pizza pizza =CreatePizza(pizzaType);
            pizza.Prepare();
            pizza.Bake();
            pizza.Cut();
            pizza.Box();
             pizza;
        }
 
        abstract Pizza CreatePizza(string pizzaType); 把工厂对象移到该方法中,该方法为抽象方法
   }

 对应于两家分店的代码:

class NYPizzaStore extends PizzaStore {
   @Override
   protected Pizza createPizza(String type) {
     )) {
       return  NYCheesePizza();
     }
     ;
   }
}
 
class ChicagoPizzaStore  PizzaStore {
     @Override
      Pizza createPizza(String type) {
         ChicagoCheesePizza();
     }
     ;
   }
}    

 我们需要建立一个 Pizza 实体类:

 Pizza {
    String name; 名称
    String dough; 面团类型
    String sauce; 酱料
    ArrayList<String> toppings = new ArrayList<String>(); 作料
 
    void prepare() {
        System.out.println("准备 " + name);
        System.out.println("揉面团...");
        System.out.println("添加酱料...");
        System.out.println("添加作料: ");
        for (int i = 0; i < toppings.size(); i++) {
            System.out.println("   " + toppings.get(i));
        }
    }
     bake() {
        System.out.println("烘烤25分钟");
    }
     cut() {
        System.out.println("把Pizza对角切片" box() {
        System.out.println("把Pizza装盒子" String getName() {
         name;
    }
}

然后需要一些具体的子类,下边定义两个子类:纽约风味的芝士披萨(NYStyleCheesePizza)、芝加哥风味的芝士披萨 (ChicageStyleCheesePizza)

class NYStyleCheesePizza  Pizza {
     NYStyleCheesePizza() { 
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
        toppings.add("Grated Reggiano Cheese");
    }
}

class ChicagoStyleCheesePizza  ChicagoStyleCheesePizza() { 
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
        toppings.add("Shredded Mozzarella Cheese"可以覆盖cut()方法
     cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}

2.2  总结

所有工厂模式都用来封装对象创建,工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。

创建者(Creator)类

 

产品类

 

简单工厂和工厂方法之间的差异?

简单工厂是在一个地方把所有的事都处理完了,然而工厂方法却是创建一个框架,让子类决定要如何实现。简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。

抽象工厂

创建工厂接口

回到上文的 Pizza 店,现在有新的需求,想要确保每家加盟店使用高质量的材料,打算创建一家生产原料的加工厂,并将原料送到各个加盟店。这个工厂负责创建原料家族中的每一种原料,工厂需要生产面团、酱料、芝士等。先为工厂定义一个接口,该接口负责所有原料:

interface PizzaIngredientFactory {
        Dough CreateDough();
 
        Sauce CreateSauce();
 
        Cheese CreateCheese();
 
        Veggies[] CreateVeggies();
 
        Pepperoni CreatePepperoni();
 
        Clams CreateClam();
}

创建一个原料厂

具体原料工厂必须实现这个接口
class NYPizzaIngredientFactory  PizzaIngredientFactory  {
         Dough CreateDough() {
             ThinCrustDough();
        }
 
         Sauce CreateSauce() {
             MarinaraSauce();
        }
 
         Cheese CreateCheese() {
             ReggianoCheese();
        }
 
         Veggies[] CreateVeggies() {
            Veggies[] veggies = new Veggies[]{ new Garlic(),new Onion(),1)">new Mushroom(),1)"> RedPepper() };
             veggies;
        }
 
         Pepperoni CreatePepperoni() {
             SlicedPepperoni();
        }
 
         Clams CreateClam() {
             FreshClams();
        }
}

重新抽象 Pizza 类

 Pizza {
        string name;
        Dough dough;
        Sauce sauce;
        Veggies[] veggies;
        Cheese cheese;
        Pepperoni pepperoni;
        Clams clam;
       public ArrayList toppings = newArrayList();
 
       void Prepare();把Prepare()方法声明成抽象,在这个方法中,我们需要收集Pizza所需的原材料,而这些原材料来自原料工厂。
Bake() { System.Console.WriteLine("Bakefor 25 minutes at 350"); } Cut() { System.Console.WriteLine("Cuttingthe pizza into diagonal slices" Box() { System.Console.WriteLine("Placepizza in official PizzaStore box" string GetName() { name; } }

重新实现 Pizza

 Pizza {
        PizzaIngredientFactory ingredientFactory;
public NYStyleCheesePizza(PizzaIngredientFactoryingredientFactory){
      //制作Pizza需要工厂提供原材料,所以每个pizza类都需要从构造器中得到一个工厂,并将工厂存储在变量中 this.ingredientFactory =ingredientFactory; name = "NY StyleSauc and Cheese Pizza"; toppings.Add("GratedReggiano Cheese"public override Prepare() { System.Console.WriteLine("Preparing" + name); dough = ingredientFactory.CreateDough(); sauce = ingredientFactory.CreateSauce(); cheese = ingredientFactory.CreateCheese(); } }

重新生产pizza

class MYPizzaStore  PizzaStore {
          override Pizza CreatePizza(string type) {
            Pizza pizza=;
            PizzaIngredientFactory ingredientFactory=  NYPizzaIngredientFactory();
            switch(type) {
                case "cheese":
                    pizza =  NYStyleCheesePizza(ingredientFactory);
                    break;
                case "veggie":
                    pizza= NYStyleVeggiePizza(ingredientFactory);
                    case "clam" NYStyleClamPizza(ingredientFactory);
                    case "pepperoni" NYStylePepperoniPizza(ingredientFactory);
                    ;
            }
             pizza;
        }
    }

通过这一系列的操作,我们引入了新类型的工厂,也就是所谓的“抽象工厂”,来创建 pizza 原来家族。通过抽象工厂所提供的接口创建产品家族,利用这个接口书写代码,我们的代码将从实际工厂解耦,以便在不同上下文中实现各式各样的工厂,制造出各种不同的产品。

定义抽象工厂模式

抽象工厂模式提供一个接口,用于创建相关或依赖对象家族,而且不需要致命具体类。

抽象工厂模式允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么,客户就从具体的产品中被解耦。

抽象工厂与工厂方法的对比

抽象工厂和工厂方法都是负责创建对象。

抽象工厂是通过对象的组合

定义了一个创建对象的接口,但由于子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。

所以利用工厂方法创建对象时,需要扩展一个类,并覆盖它的工厂方法。

整个工厂方法模式,只不过就是通过子类来创建对象,这种做法,客户只需要知道他们所使用的抽象类型就可以了,而由子类负责决定具体类型。将客户从具体类型中解耦。

工厂方法是继承。

抽象工厂方法是将一群相关的产品集合起来,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

 

 参考文章

https://blog.csdn.net/xuemoyao/article/details/53437609

https://www.cnblogs.com/lzhp/p/3375041.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结