《设计模式》工厂模式

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

有一个披萨的项目:

  • 披萨的种类很多,有 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. 小结

工厂模式的意义

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

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

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


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

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

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


相关文章
|
6月前
|
设计模式 存储 Java
设计模式-工厂模式
设计模式-工厂模式
67 1
|
6月前
|
设计模式
设计模式【二】:工厂模式
设计模式【二】:工厂模式
45 0
|
设计模式 Java C++
设计模式之工厂模式详解和应用
设计模式之工厂模式详解和应用
68 0
|
2月前
|
设计模式 Java 关系型数据库
设计模式——工厂模式
工厂模式介绍、静态简单工厂模式、工厂方法模式、抽象工厂模式、JDK 源码分析
设计模式——工厂模式
|
5月前
|
设计模式 数据格式 XML
设计模式-工厂模式-1-1
【6月更文挑战第10天】本文介绍了工厂模式的两种主要类型:简单工厂和工厂方法。简单工厂模式通过工厂类动态创建对象,例如根据配置文件后缀选择不同解析器。为提高可读性和复用性,可将创建逻辑封装到独立类中。当需添加新解析器时,可能涉及对工厂类的修改,但这在偶尔调整时可接受。工厂方法模式则通过多态消除if分支,增加扩展性,更符合开闭原则。当需要新增解析器时,只需创建实现特定接口的新工厂类。
32 2
设计模式-工厂模式-1-1
|
5月前
|
设计模式 XML 缓存
设计模式-工厂模式-1-2
【6月更文挑战第11天】工厂模式用于封装对象创建,但当load函数与工厂类耦合时,问题出现。为解决此问题,引入了工厂的工厂,如`RuleConfigParserFactoryMap`,它创建并缓存工厂对象,简化了代码修改。然而,过多的Factory类会增加复杂性,简单工厂模式在此类应用中更为适用。当对象创建逻辑复杂,需组装其他对象或避免if-else时,采用工厂方法模式。抽象工厂则处理多维度分类的对象创建。总结:工厂模式的核心价值在于封装变化、代码复用、隔离复杂性和控制复杂度,适用于创建逻辑复杂的情况,否则直接使用new操作即可。
27 5
|
6月前
|
设计模式 消息中间件 Java
设计模式之工厂模式(C++)
设计模式之工厂模式(C++)
88 0
|
6月前
|
设计模式 算法 uml
C++设计模式(工厂模式)
C++设计模式(工厂模式)
93 1
C++设计模式(工厂模式)
|
6月前
|
设计模式 前端开发 API
【设计模式】之工厂模式
工厂模式是一种常用的创建对象的设计模式,它通过封装对象的创建逻辑,提供统一的接口,实现了代码的解耦和可扩展性。在实际开发中,可以根据具体需求选择是否使用工厂模式来创建对象。工厂模式可以应用于任何需要创建对象的场景。通过使用工厂模式,我们可以提高代码的可维护性、可扩展性和可测试性,使得代码更加灵活和易于理解。
77 0
|
设计模式 前端开发 Java
设计模式之工厂模式(1)
工厂模式是一种对象创建型模式,它提供了一种创建对象的最佳实践。在工厂模式中,我们在创建对象时不使用 new 关键字,而是通过调用工厂方法来创建对象。工厂方法是一种在子类中定义的方法,该方法负责实例化对象。工厂方法可以返回不同的对象类型,因此工厂模式可以创建一组相关或不相关的对象。这样就可以将对象的创建和使用解耦。
61 0