Java 设计模式之工厂模式(Factory)

一、简单工厂

简单工厂是一种编程习惯,把变化的代码(new 对象)封装在一个工厂里

用户需求:客户想要在pizza店orderPizza

需求分析:

  • 首先只有1个pizza店,有不同种类的pizza,不同客户order不同种类的pizza
  • 如果在pizza店的类里用 if else 编码,一旦有新种类就需要改pizza店的代码
  • 这里新建一个对象,封装创建pizza对象的部分,这个对象称之为工厂。这样一来,再有新类型的pizza,只要修改工厂即可,pizza店不关注pizza的具体生产过程
  • 简单工厂是一个工厂根据不同参数生产出不同的产品(所需对象),一个工厂类对应多个不同的产品类

类图设计

  • 工厂的客户:PizzaStore,要购买预定各种各样的pizza
  • 创建Pizza的简单工厂:SimplePizzaFactory,唯一用到具体pizza类的地方
  • 工厂的产品:Pizza,定义为抽象类
  • 工厂的具体产品:CheesePizza,ClamPizza等

Java 设计模式之工厂模式(Factory)_第1张图片

代码示例

PizzaStore代码

package Factory.SimpleFactory;

public class PizzaStore {
    SimplePizzaFactory factory;

    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    public Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

SimplerPizzaFactory代码

package Factory.SimpleFactory;

public class SimplePizzaFactory {
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        switch (type) {
            case "cheese":
                pizza = new CheesePizza();
                break;
            case "clam":
                pizza = new ClamPizza();
                break;
            case "veggie":
                pizza = new VeggiePizza();
                break;
            default:
                break;
        }
        return pizza;
    }
}

这就是简单工厂,用一个新的对象(SimplePizzaFactory)封装创建对象的代码,这个新的对象就是“工厂”。

二、工厂方法模式

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

依然是上面的场景

用户需求:不只有一个pizza店,有很多家,不同客户order不同种类的pizza

需求分析:

  • 对于简单工厂,这样就需要修改工厂类,违反了开闭原则
  • 所以这里用工厂方法模式,允许子类去做决定
  • 多个工厂类,多个产品类,工厂和产品一一对应,如果有新的产品,新增工厂类,这样比简单工厂模式更加解耦

类图设计:

  • PizzaStore:是创建者(Creator)类,定义了个一个抽象的工厂方法(abstract Pizza createPizza(String type),让子类实现此方法制造产品,创建者不需要知道在制造哪种产品
  • NYPizzaStore:PizzaStore的子类,实现createPizza方法,用来制造产品
  • Pizza:产品类
  • NYStyleCheesePizza:具体的产品

Java 设计模式之工厂模式(Factory)_第2张图片

代码示例:

Pizza代码

package Factory.FactoryMethod;

import java.util.ArrayList;

public abstract class Pizza {
    String name;
    String dough;
    String sauce;
    ArrayList toppings = new ArrayList();

    void prepare() {
        System.out.println("Preparing " + name);
        System.out.println("Tossing dough...");
        System.out.println("Adding sauce...");
        System.out.println("Adding topping: ");
        for (int i = 0; i < toppings.size(); i++) {
            System.out.println(" " + toppings.get(i));
        }
    }

    void bake() {
        System.out.println("Bake for 25 mins at 350");
    }

    void cut() {
        System.out.println("Cutting the pizza into diagonal slices");
    }

    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }
}

NYStyleCheesePizza代码

package Factory.FactoryMethod;

public class NYStyleCheesePizza extends Pizza {
    public NYStyleCheesePizza() {
        name = "NY style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";

        toppings.add("Grated Reggiano Cheese");
    }
}

ChicagoStyleCheesePizza代码,重写了cut方法 

package Factory.FactoryMethod;

public class ChicagoStyleCheesePizza extends Pizza {
    public ChicagoStyleCheesePizza() {
        name = "Chicago Style Deep Dish Cheese Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";

        toppings.add("Shredded Mozzarella Cheese");
    }

    @Override
    public void cut() {
        System.out.println("Cutting the Pizza into square slices");
    }
}

PizzaStore 代码 

package Factory.FactoryMethod;


public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

    protected abstract Pizza createPizza(String type);
}

 ChicagoPizzaStore 代码 

package Factory.FactoryMethod;

public class ChicagoPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        switch (type) {
            case "cheese":
                pizza = new ChicagoStyleCheesePizza();
                break;
            default:
                pizza = null;
        }
        return pizza;
    }
}

NYPizzaStore代码

package Factory.FactoryMethod;

public class NYPizzaStore extends PizzaStore {
    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza=null;
        switch (type){
            case "cheese":
                pizza=new NYStyleCheesePizza();
                break;
            default:
                pizza=null;
        }
        return pizza;
    }
}

 测试类代码

package Factory.FactoryMethod;

public class PizzaTestDrive {
    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();

        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("wpp ordered a " + pizza.getName());
        pizza = chicagoStore.orderPizza("cheese");
        System.out.println("ypp ordered a " + pizza.getName());
    }
}

小结:

  • 工厂方法模式是定义了一个创建对象的接口,如果只有一个工厂对象(简单工厂),把上面工厂方法类图处理后像什么?(可以看看简单工厂的类图)

Java 设计模式之工厂模式(Factory)_第3张图片

  • 产品抽象类,产品类;工厂抽象类,工厂类,一一对应
    • 优点:不用像简单工厂那样,需要修改工厂类,只需要新增即可,遵从了开闭原则,比简单工厂更加解耦
    • 缺点:新增的东西比较多,工作量会比较大
  • 设计原则:要依赖抽象,不要依赖具体类
  • abstract product factoryMethod(String type);
    • 工厂方法是抽象的,依赖子类处理对象的创建
    • 工厂方法必须返回一个产品
    • 工厂方法将客户也就是超类中的代码例如orderPizza和实际创建产品的代码分离开来

三、抽象工厂模式

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

类图设计:

Java 设计模式之工厂模式(Factory)_第4张图片

代码示例:

  • AbstractFactory:抽象工厂定义了一个接口,所有具体工厂必须实现此接口,接口包含一组生产产品的方法
package Factory.AbstractFactory;

public interface AbstractFactory {
    public AbstractProductA ProductA();
    public AbstractProductB ProductB();
}
  • ConcreteFactory:具体工厂实现不同产品家族,客户只要使用其中一个工厂生产产品,完全不需要实例化任何产品对象
package Factory.AbstractFactory;

public class ConcreteFactory1 implements AbstractFactory {
    @Override
    public AbstractProductA ProductA() {
        return new ProductA1();
    }

    @Override
    public AbstractProductB ProductB() {
        return new ProductB1();
    }
}
  • AbstractProduct:整个产品家族(A/B/C等等),每个具体工厂都可以生产一整组的产品(A+B+C+等等)

具体应用场景:

依然是上面的pizza店,要生产pizza产品就需要原料,有面团、酱料、芝士、海鲜作料,这每一种原料都可以看做是工厂方法模式中的一种产品对象(如,不同的面料就会有不同的面团,番茄酱和芝麻酱就是不同的酱料,也就是不同的具体对象),而这些产品对象组合起来才是一个抽象工厂模式下的一个完整产品pizza。抽象工厂模式更关注的是多维度的产品家族,是对象组合为一个完整的产品,这里就不贴具体代码了,感兴趣的同学可以自己搞一搞。

小结:

  • 抽象工厂的任务是定义一个负责创建一组产品的接口,接口内的每个方法都负责创建一个具体产品(工厂方法模式)如果抽象工厂里面只有一个生产方法(足够生产所需对象),这时候的抽象工厂类图像什么?(可以看看工厂方法模式的类图)

Java 设计模式之工厂模式(Factory)_第5张图片


总结:

  • 简单工厂——工厂方法模式——抽象工厂模式,是由简入繁,最开始的单一工厂只负责创建对象(简单工厂),到后来的多个工厂对应多个产品(工厂方法模式),再到最后的产品家族的整个创建模式(抽象工厂模式)
  • 所有工厂模式都是用来封装对象的创建的,也就是“那部分变化的代码”,都应减少程序和具体类之间的依赖。
  • 工厂方法把对象的创建委托给子类,子类实现工厂方法来创建对象
  • 抽象工厂使用对象组合,组合成一个完整的产品

你可能感兴趣的:(Java,设计模式)