加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-14 04:45:09 所属栏目:百科 来源:网络整理
导读:设计模式文章 中介者模式 代理模式 抽象工厂模式详解 —— head first 设计模式 装饰者模式 适配器模式 策略模式 观察者模式 建造者模式 (Builder) 项目实例 假设你有一家 pizza 店,你有很多种 pizza,要在系统中显示你所有 pizza 种类。实现这个功能并不难

设计模式文章

中介者模式

代理模式

抽象工厂模式详解 —— 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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读