《设计模式》工厂模式

简介: 《设计模式》工厂模式

有一个披萨的项目:

  • 披萨的种类很多,有 GreekPizzaCheesePizza
  • 披萨的制作过程有 preparebakecutbox
  • 完成披萨店的订购功能

使用传统的方式来完成,其 UML 图如下所示:

2e718f6de6d94987ae2f2182c528d9c8.png

Pizza 类代码如下:

public abstract class Pizza {
    protected String name; //名字
    public abstract void prepare();
    public void bake() {
        System.out.println(name+"baking");
    }
    public void cut() {
        System.out.println(name+"cutting");
    }
    public void box() {
        System.out.println(name+"boxing");
    }
    public void setName(String name) {
        this.name = name;
    }
}

CheesePizza 类代码如下:

public class CheesePizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("制作奶酪披萨,准备原材料");
    }
}

GreekPizza 类代码如下:

public class GreekPizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("制作希腊披萨,准备原材料");
    }
}

PepperPizza 类代码如下:

public class PepperPizza extends Pizza{
    @Override
    public void prepare() {
        System.out.println("给胡椒披萨准备原材料");
    }
}

rderPizza 类代码如下:

public class OrderPizza {
    //构造器
    public OrderPizza() {
        Pizza pizza = null;
        String orderType;  //订购披萨的类型
        do {
            orderType = getType();
            if (orderType.equals("greek")) {
                pizza = new GreekPizza();
                pizza.setName("希腊披萨");
            } else if (orderType.equals("cheese")) {
                pizza = new CheesePizza();
                pizza.setName("奶酪披萨");
            } else if (orderType.equals("pepper")) {
                pizza = new PepperPizza();
                pizza.setName("胡椒披萨");
            } else {
                break;
            }
            //输出pizza制作过程
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }
}

1. 简单工厂模式

如果想要新增一个 Pizza 类,则会涉及到客户端 OrderPizza 类,这种方式违背了设计模式的开闭原则,对修改关闭,对扩展开放。因此,可以考虑将创建 Pizza 对象封装到一个类中,这样有新的 Pizza 种类的时候,只需要修改该类即可,其他有创建到 Pizza 对象的代码就不需要修改,可以使用简单工厂模式。

定义:简单工厂模式属于创建型模式,是工厂模式的一种,它是由一个工厂对象决定创建出哪一种产品类的实例。定义一个创建对象的类,由这个类来封装实例化对象的行为。

使用场景:当用到大量的创建某种、某类或者某批对象的时候就会使用到工厂模式。

使用简单工厂模式重构代码,其 UML 图和实现代码如下所示:2e718f6de6d94987ae2f2182c528d9c8.png

简单工厂类 SimpleFactory

public class SimpleFactory {
    //根据orderType返回对应的Pizza对象
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        System.out.println("使用简单工厂模式");
        if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName("希腊披萨");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName("奶酪披萨");
        } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }
    //根据orderType返回对应的Pizza对象,简单工厂模式也叫静态工厂模式
    public static Pizza createPizza2(String orderType) {
        Pizza pizza = null;
        System.out.println("使用简单工厂模式");
        if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName("希腊披萨");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName("奶酪披萨");
        } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }
}

订购披萨类 OrderPizza

public class OrderPizza {
    Pizza pizza = null;
    String orderType = "";
    //构造器
    public OrderPizza() {
        do {
            orderType = getType();
            pizza = SimpleFactory.createPizza2(orderType);
            if (pizza != null) { //订购成功
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("订购披萨失败");
                break;
            }
        } while (true);
    }
    //获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}

2. 工厂方法模式

此时披萨有一个新的需求,客户在点披萨时,可以点不同产地的披萨。例如,北京的奶酪披萨、北京的胡椒披萨或者上海的奶酪披萨等等。虽然依然使用简单工厂模式,创建不同的简单工厂类,例如 BJCheesePizza、BJPepperPizza,但是考虑到项目的规模以及软件的可维护性和可扩展性并不是特别好,这里考虑使用工厂方法模式。

  • 将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。

定义:定义一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法模式将对象的实例化推迟到子类。

使用工厂方法模式思想设计的 UML 图如下所示:

2e718f6de6d94987ae2f2182c528d9c8.png

Pizza

public abstract class Pizza {
    protected String name; //名字
    public abstract void prepare();
    public void bake() {
        System.out.println(name+"baking");
    }
    public void cut() {
        System.out.println(name+"cutting");
    }
    public void box() {
        System.out.println(name+"boxing");
    }
    public void setName(String name) {
        this.name = name;
    }
}

BJCheesePizza

public class BJCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京奶酪披萨");
        System.out.println("北京的奶酪披萨,准备原材料");
    }
}

BJPepperPizza

public class BJPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("北京的胡椒披萨");
        System.out.println("北京的胡椒披萨,准备原材料");
    }
}

SHCheesePizza

public class SHCheesePizza extends Pizza{
    @Override
    public void prepare() {
        setName("上海的奶酪披萨");
        System.out.println("上海的奶酪披萨,准备原材料");
    }
}

SHPepperPizza

public class SHPepperPizza extends Pizza{
    @Override
    public void prepare() {
        setName("上海的胡椒披萨");
        System.out.println("上海的胡椒披萨,准备原材料");
    }
}

OrderPizza

public abstract class OrderPizza {
    //定义一个抽象方法createPizza,让各个工厂子类自己实现
    abstract Pizza createPizza(String orderType);
    //构造器
    public OrderPizza() {
        Pizza pizza = null;
        String orderType = "";
        do {
            orderType = getType();
            pizza = createPizza(orderType);
            //制作过程
            if (pizza != null) { //订购成功
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("订购披萨失败");
                break;
            }
        } while (true);
    }
    //获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}

BJOrderPizza

public class BJOrderPizza extends OrderPizza{
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

SHOrderPizza

public class SHOrderPizza extends OrderPizza{
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new SHCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new SHPepperPizza();
        }
        return pizza;
    }
}

3. 抽象工厂模式

定义

定义了一个接口用于创建相关或有依赖关系的对象簇,而无需指明具体的类

将工厂抽象成两层:AbsFactory(抽象工厂)和具体实现的工厂子类。开发人员根据创建对象类型使用对应的工厂子类,这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

从设计层面看,抽象工厂模式就是对简单工厂模式的进一步抽象。

使用抽象工厂模式重构披萨项目,其 UML 图如下所示:

2e718f6de6d94987ae2f2182c528d9c8.png

.AbsFactory 接口

public interface AbsFactory {
    //让下面的工厂子类具体实现
    Pizza createPizza(String orderType);
}

BJFactory

public class BJFactory implements AbsFactory{
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("使用的是抽象工厂模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

SHFactory

public class SHFactory implements AbsFactory{
    @Override
    public Pizza createPizza(String orderType) {
        System.out.println("使用的是抽象工厂模式");
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new SHCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new SHPepperPizza();
        }
        return pizza;
    }
}

OrderPizza

public abstract class OrderPizza {
    AbsFactory absFactory;
    //构造器
    public OrderPizza(AbsFactory absFactory) {
        Pizza pizza = null;
        String orderType = "";
        this.absFactory = absFactory;
        do {
            orderType = getType();
            pizza = absFactory.createPizza(orderType);
            //制作过程
            if (pizza != null) { //订购成功
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println("订购披萨失败");
                break;
            }
        } while (true);
    }
    //获取客户希望订购的披萨种类
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}

4. 工厂模式在 JDK 中的应用

JDK 中的 Calendar 类中就使用了简单工厂模式,Calendar 类中的静态方法 createCalendar 部分代码代码如下:

if (aLocale.hasExtensions()) {
     String caltype = aLocale.getUnicodeLocaleType("ca");
     if (caltype != null) {
         switch (caltype) {
           case "buddhist":
           cal = new BuddhistCalendar(zone, aLocale); //extends GregorianCalendar
               break;
           case "japanese":
               cal = new JapaneseImperialCalendar(zone, aLocale); //extends Calendar
               break;
           case "gregory":
               cal = new GregorianCalendar(zone, aLocale); //extends Calendar
               break;
         }
     }
}

从以上代码可以看到,其实 Calendar 相当于一个简单工厂,根据不同的caltype来创建对应的 Calendar 对象。

5. 小结

工厂模式的意义

将实例化的代码提取处理出来,放到一个类中进行统一的管理和维护,达到与主项目解耦,提高系统可可扩展性和可维护性。

三种模式:简单工厂模式、工厂方法模式、抽象工厂模式。

工厂模式的依赖抽象原则:


创建对象实例时,不要直接使用直接创建对象,而是将创建对象的工作放在一个工厂的方法中再返回。

不要让类继承具体的类,而是继承抽象类或接口。

不要覆盖基类中已经实现的方法。


相关文章
|
5天前
|
设计模式 存储 Java
设计模式-工厂模式
设计模式-工厂模式
45 1
|
7月前
|
设计模式 Java
设计模式~工厂模式-03
工厂模式 简单工厂模式 优点: 缺点: 工厂方法模式
35 0
|
5天前
|
设计模式 消息中间件 Java
设计模式之工厂模式(C++)
设计模式之工厂模式(C++)
41 0
|
5天前
|
设计模式 算法 uml
C++设计模式(工厂模式)
C++设计模式(工厂模式)
50 1
C++设计模式(工厂模式)
|
6月前
|
设计模式 前端开发 Java
设计模式之工厂模式(1)
工厂模式是一种对象创建型模式,它提供了一种创建对象的最佳实践。在工厂模式中,我们在创建对象时不使用 new 关键字,而是通过调用工厂方法来创建对象。工厂方法是一种在子类中定义的方法,该方法负责实例化对象。工厂方法可以返回不同的对象类型,因此工厂模式可以创建一组相关或不相关的对象。这样就可以将对象的创建和使用解耦。
34 0
|
6月前
|
设计模式 Java C#
设计模式之工厂模式(2)
接着,我们定义一个抽象工厂类AbstractFactory,它有两个抽象方法createShape和createColor,分别返回一个Shape对象和一个Color对象: java
27 0
|
10月前
|
设计模式
【设计模式】工厂模式
【设计模式】工厂模式
|
11月前
|
设计模式 Java 数据库
设计模式之工厂模式(一)
设计模式之工厂模式
50 0
|
11月前
|
设计模式 SQL 搜索推荐
设计模式之工厂模式(二)
设计模式之工厂模式
88 0
|
12月前
|
设计模式 Java 测试技术
浅谈设计模式 - 工厂模式(六)
在第一篇里面已经介绍过简单工厂了,但是工厂模式里面不仅仅是简单工厂,还存在工厂方法和抽象工厂,并且从严格意义来讲简单工厂不能算是一种设计模式,本次的文章针对工厂的进化来展开讲一讲工厂模式的三种常见形式:简单工厂、工厂方法、抽象工厂。
51 0