工厂模式

  1. 简单工厂:
    1. 优点
    2. 缺点
  2. 工厂模式:
    1. 创建者:
    2. 产品:
    3. 工厂好处:
  3. 依赖倒置原则(Dependency Inversion Principle):
  4. 抽象工厂:
  5. 比较抽象工厂模式和工厂模式

问题回顾:

ArrayList<String> list=new ArrayList<>();

代码绑定者具体实现类,会让代码脆弱且缺乏弹性。我们可以使用接口使它更有弹性:

List<String> list = new ArrayList<>();
Duck duck = new MallardDuck();

但有一些要实例化的具体类,究竟实例化为哪一个类,需要由运行时的条件决定。一旦有变化或扩展,就必须重新打开上面那段代码检查修改,这将令维护更新变得困难。

在这个例子中,new一个对象没有错,真正有问题的是“改变”没被隔离出来,影响了new的使用。

设计原则:类应当对扩展开放,对修改关闭。

针对接口编程可以隔离掉系统以后将发生的一大堆改变。我们需要一种方法找出会变化的部分,把它们从不变的部分隔离出来。

再看一个例子:

Pizza orderPizza(String type){
    Pizza pizza;
    
    /*************创建对象部分************/
    if(type.equals("a"))pizza=new APizza();
    else if(type.equals("b"))pizza=new BPizza();
    else{/*...*/}
    /***********************************/
    
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    return pizza;
}

如果披萨的种类不断增加,那么这段代码就必须一改再改。进而我们知道,如果在代码中new某个对象(实例化某个对象),将使orderPizza()出问题,无法让orderPizza()对修改关闭。所以我们得做一些封装。

将创建Pizza对象转移到orderPizza()之外,给专职创建披萨的新对象,即工厂。

**工厂(Factory)**处理创建对象的细节

简单工厂:

public class SimplePizzaFactory{
    public Pizza createPizza(String type){
        Pizza pizza=null;
        if(type.equals("a"))pizza=new APizza();
        else if(type.equals("b"))pizza=new BPizza();
        else{/*...*/}
        return pizza;
    }
}

利用静态方法定义一个简单工厂:静态工厂:

public class SimplePizzaFactory{
    public static Pizza createPizza(String type){
        Pizza pizza=null;
        if(type.equals("a"))pizza=new APizza();
        else if(type.equals("b"))pizza=new BPizza();
        else{/*...*/}
        return pizza;
    }
}
优点

​ 帮助封装。客户端可以更好的面向接口编程。
​ 解耦。客户端不需要知道实现类。

缺点

​ 需要理解参数的意义,增加复杂度。
​ 静态工厂不方便扩展子类。

简单工厂其实不是一种设计模式,更像是一种编程习惯

升级原有代码,用工厂去创建披萨:

public class PizzaStore{
    SimplePizzaFactory factory;
    
    //构造注入
    public PizzaStore(SimplePizzaFactory factory){
        thi.factory=factory;
    }
    
    Pizza orderPizza(String type){
        Pizza pizza=factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

工厂模式:

让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。工厂模式的组成元素:创建者类和产品类

创建者:
/*创建者类*/
public abstract class PizzaStore{
	Pizza orderPizza(String type){
        Pizza pizza = createPizza(type);	//创建对象的业务
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    
    protected abstract Pizza createPizza(String type);	//让子类决定该创建的对象是什么
}
//创建者类:纽约披萨店
public class NYPizzaStore extends PizzaStore{
    //子类决定该创建的对象是什么
    Pizza createPizza(String item){
        if(item.equals("cheese")){
            return new NYStyleCheesePizza();
        }else if(item.equals("clam")){
            return new NYStyleClamPizza();
        }else if(...){
            ...
        }return null;
    }
}

//创建者类:洛杉矶披萨店
public class LAPizzaStore extends PizzaStore{
    //子类决定该创建的对象是什么
    Pizza createPizza(String item){
        if(item.equals("cheese")){
            return new LAStyleCheesePizza();
        }else if(item.equals("clam")){
            return new LAStyleClamPizza();
        }else if(...){
            ...
        }return null;
    }
}

....
产品:
public abstract class Pizza{
    String name;
    String dough;
    String sauce;
    
    void prepare(){
        System.out.println("preparing...");
    }
    void bake(){
        System.out.println("baking...");
    }
    void cut(){
        System.out.println("cutting...");
    }
    void box(){
        System.out.println("boxing...");
    }

    public String getName() {
        return name;
    }
}
...
public class LAStyleCheesePizza extends Pizza{
    LAStyleCheesePizza(){
        name="NEW YORK STYLE CHEESE PIZZA";
        dough="dough";
        sauce="sauce";
        toppings.add("LA Cheese");
    }

    @Override
    void cut() {
        System.out.println("cutting in LA Style...");
    }
}
...
public class NYStyleCheesePizza extends Pizza {
    NYStyleCheesePizza(){
        name="NEW YORK STYLE CHEESE PIZZA";
        dough="dough";
        sauce="sauce";
        toppings.add("Cheese");
    }
}

Test:

public class Test {
    public static void main(String[] args) {
        PizzaStore nyStore=new NYPizzaStore();
        PizzaStore laStore=new LAPizzaStore();
        System.out.println("吃一个"+nyStore.orderPizza("cheese").getName());
        System.out.println();
        System.out.println("吃一个"+laStore.orderPizza("cheese").getName());
    }
}

工厂方法

  • 是抽象的,具体的实现封装在子类中。
  • 将返回一个产品类
  • 将业务和实际创建具体产品的代码分隔开来。
工厂好处:
  • 将创建对象的代码集中在一个对象或方法中,可以避免代码中的重复,并更方便以后的维护。也意味着客户在实例化对象时,只会依赖于接口而不是具体类。帮助我们针对接口编程。

依赖倒置原则(Dependency Inversion Principle):

设计原则:要依赖抽象,不要依赖具体类

不能让高层组件依赖底层组件,不管是高层底层组件,都应当依赖于抽象

PizzaStore是高层组件,披萨实现是底层组件。

避免违反依赖导致原则的指导方针:

  • 变量不可以持有具体类的引用
    如果使用new,就会持有具体类的引用,你可以改用工厂方法来避免这么做
  • 不要让类派生自具体类
    如果派生自具体类,就会依赖具体类。请派生自一个抽象(接口或抽象类)
  • 不要覆盖基类中已实现的方法
    如果覆盖基类已实现的方法,那么这个基类就不适合作为被继承的抽象。基类中已实现的方法要由子类共享。

抽象工厂:

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

通过抽象工厂所提供的接口,可以创建产品的家族,利用这个接口书写代码,我们的代码将从实际工厂解耦,以便在不同的上下文实现各式各样的工厂,制造不同的商品。

我们引入了抽象工厂来创建 “披萨原料”家族 。

披萨店:

public abstract class PizzaStore {
    protected abstract Pizza createPizza(String item);

    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        System.out.println("--- Making a " + pizza.getName() + " ---");
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

/*************纽约披萨店***************/
public class NYPizzaStore extends PizzaStore {
    protected Pizza createPizza(String item) {
        Pizza pizza = null;
        // 原料工厂
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
        if (item.equals("cheese")) {
            // 注入抽象原料工厂
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese Pizza");
        } else if (item.equals("veggie")) {
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("New York Style Veggie Pizza");
        } else if (item.equals("clam")) {
            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("New York Style Clam Pizza");
        } else if (item.equals("pepperoni")) {
            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("New York Style Pepperoni Pizza");
        }
        return pizza;
    }
}

/*************芝加哥披萨店***************/
public class ChicagoPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String item) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory();
        switch (item){
            case "cheese":
                pizza = new CheesePizza(ingredientFactory);
                pizza.setName("Chicago Style Cheese Pizza");
                break;
            case "veggie":
                pizza = new VeggiePizza(ingredientFactory);
                pizza.setName("Chicago Style Veggie Pizza");
                break;
            case "clam":
                pizza = new ClamPizza(ingredientFactory);
                pizza.setName("Chicago Style Clam Pizza");
                break;
            case "pepperoni":
                pizza = new PepperoniPizza(ingredientFactory);
                pizza.setName("Chicago Style Pepperoni Pizza");
                break;
        }
        return pizza;
    }
}

披萨:

public abstract class Pizza {
    String name;
    String dough;
    String sauce;
    ArrayList toppings=new ArrayList();
    void prepare(){
        System.out.println("preparing "+name);
    }
    void bake(){
        System.out.println("baking...");
    }
    void cut(){
        System.out.println("cutting...");
    }
    void box(){
        System.out.println("boxing...");
    }
    public String getName() {
        return name;
    }
}

/*******************************************************/
public class CheesePizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;
    //披萨构造函数注入抽象原料工厂,运行时动态地注入对应地区原料工厂,造出对应地区口味披萨
    public CheesePizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }
    void prepare() {
        System.out.println("Preparing " + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }
}

/*******************************************************/
public class ClamPizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;
    public ClamPizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }
    void prepare() {
        System.out.println("Preparing " + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
        clam = ingredientFactory.createClam();
    }
}

......

原料工厂:

public interface PizzaIngredientFactory {
    Dough createDough();
    Sauce createSauce();
    Cheese createCheese();
    Veggies[] createVeggies();
    Pepperoni createPepperoni();
    Clams createClam();
}

/*********************纽约原料工厂***********************/
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
    public Dough createDough() {
        return new ThinCrustDough();
    }
    public Sauce createSauce() {
        return new MarinaraSauce();
    }
    public Cheese createCheese() {
        return new ReggianoCheese();
    }
    public Veggies[] createVeggies() {
        Veggies veggies[] = {new Garlic(), new Onion(), new Mushroom(), new RedPepper()};
        return veggies;
    }
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }
    public Clams createClam() {
        return new FreshClams();
    }
}

/*********************芝加哥原料工厂***********************/
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {
    @Override
    public Dough createDough() {
        return new ThickCrustDough();
    }
    @Override
    public Sauce createSauce() {
        return new PlumTomatoSauce();
    }
    @Override
    public Cheese createCheese() {
        return new MozzarellaCheese();
    }
    @Override
    public Veggies[] createVeggies() {
        Veggies[] veggies = {
                new BlackOlives(),
                new Spinach(),
                new Eggplant()
        };
        return veggies;
    }
    @Override
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }
    @Override
    public Clams createClam() {
        return new FrozenClams();
    }
}

......

一图胜千言

image-20200328211526914

抽象工厂的任务是定义一个负责创建一组产品的接口这个接口内的每一个方法都负责创建一个具体产品,同时我们利用实现抽象工厂的子类来提供这些方法的具体做法。

在抽象工厂中利用工厂方法实现生产方法是相当自然的。

比较抽象工厂模式和工厂模式

工厂方法 抽象工厂
负责创建对象,采用继承方式:利用工厂方法创建对象时需要扩展一个类,并覆盖它的工厂方法,即通过子类来创建对象。 负责创建对象,采用组合方式:提供一个用来创建产品家族的抽象类型,这个类型的子类定义了产生产品的方法。要想使用抽象工厂,必须先实例化它,然后将实例传入针对抽象类型所写的代码中。
抽象创建者(creator)中的方法 经常会用到子类所创建的具体类型 实现抽象类型的具体工厂 经常使用工厂方法来创建他们的产品
将客户代码从需要实例化的具体类中解耦。如果目前不知道将来需要实例化哪些类时,也可以用工厂模式。 创建产品家族,或想让制造的相关产品集合起来时,可以使用抽象工厂模式

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,邮件至 708801794@qq.com

文章标题:工厂模式

文章字数:2.4k

本文作者:梅罢葛

发布时间:2020-03-28, 14:21:29

最后更新:2020-03-28, 22:23:16

原始链接:https://qiurungeng.github.io/2020/03/28/%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/
目录
×

喜欢就点赞,疼爱就打赏