• 设计模式-工厂设计模式


    完成披萨店订购功能:披萨店根据用户需要的披萨种类制作披萨

    • 披萨的种类很多(比如 GreekPizz、CheesePizz 等)
    • 披萨的制作流程为prepare、bake、cut、box

    1.传统方法

    1.1 类图

    在这里插入图片描述

    1.2 代码实现

    // Pizza.java
    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    // CheesePizza.java
    public class CheesePizza extends Pizza {
        @Override
        public void prepare() {
            System.out.println("给制作奶酪披萨准备原材料 ");
        }
    }
    // GreekPizza.java
    public class GreekPizza extends Pizza {
        @Override
        public void prepare() {
            System.out.println("给希腊披萨准备原材料 ");
        }
    }
    // 新增加的披萨
    // PepperPizza.java
    public class PepperPizza extends Pizza {
        @Override
        public void prepare() {
            System.out.println("给胡椒披萨准备原材料 ");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    // OrderPizza.java(相当于披萨店)
    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);
        }
    
        // 获取客户希望订购的披萨种类
        private String getType() {
            try {
                BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
                System.out.println("输入pizza种类:");
                String str = strin.readLine();
                return str;
            } catch (IOException e) {
                e.printStackTrace();
                return "";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    // PizzaStore.java
    // 相当于一个客户端,发出订购
    public class PizzaStore {
        public static void main(String[] args) {
            new OrderPizza();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1.3 优缺点

    • 好理解,易操作
    • 违反了设计模式的ocp原则(即对扩展开放,对修改关闭):
      • 上面新增了一个披萨种类后,OrderPizza代码也需要相应修改
      • 如果有OrderPizza2等(即有多家披萨店),都需要修改代码

    2.简单工厂模式

    把创建Pizza对象封装到一个类中,当有新的Pizza种类时,只需要修改该类就可,其它有创建到Pizza对象的代码就不需要修改了

    2.1 特点

    • 由一个工厂对象决定创建出哪一种产品类的实例

    • 定义一个创建对象的类,由这个类来封装实例化对象的行为

    • 当用到大量的创建某种、某类或者某批对象时,会使用到该模式

    2.2 类图

    在这里插入图片描述

    2.3 代码实现

    相当于每个披萨店找了一个代工厂加工披萨,每次新增一种披萨后只需要代工厂修改代码,披萨店不需要修改代码

    // SimpleFactory.java
    // 简单工厂模式(静态工厂模式)
    public class SimpleFactory {
        // 可以改为静态方法,使得调用时代码更加简洁
        // (OrderPizza类中不需要在构造器中传入工厂类)
        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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    // OrderPizza.java
    public class OrderPizza {
        SimpleFactory simpleFactory;
        Pizza pizza = null;
    
        public OrderPizza(SimpleFactory simpleFactory) {
            setFactory(simpleFactory);
        }
    
        public void setFactory(SimpleFactory simpleFactory) {
            String orderType; // 用户需要披萨类别
    
            this.simpleFactory = simpleFactory;  // 设置简单工厂对象
    
            do {
                orderType = getType();
                pizza = this.simpleFactory.createPizza(orderType);
    
                if (pizza != null) {  // 订购成功
                    pizza.prepare();
                    pizza.bake();
                    pizza.cut();
                    pizza.box();
                } else {
                    System.out.println("订购披萨失败");
                    break;
                }
            } while (true);
        }
        
    	...getType()...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    // 相当于一个客户端,发出订购
    public class PizzaStore {
        public static void main(String[] args) {
            new OrderPizza(new SimpleFactory());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.工厂方法模式

    客户在点披萨时,除了点不同类型的披萨,还想点不同地方的披萨,比如北京的奶酪pizza或者是伦敦的奶酪pizza。使用简单工厂模式,可以创建不同的简单工厂类,比如BJPizzaSimpleFactoryLDPizzaSimpleFactory 等等,但可维护性和可扩展性不好

    3.1 特点

    • 定义了一个创建对象的抽象方法,由子类决定要实例化的类
    • 将对象的实例化推迟到子类

    3.2 类图

    在这里插入图片描述

    3.3 代码实现

    // BJCheesePizza.java
    public class BJCheesePizza extends Pizza {
        @Override
        public void prepare() {
            setName("北京的奶酪pizza");
            System.out.println("北京的奶酪pizza准备原材料");
        }
    } 
    // BJPepperPizza LDCheesePizza LDPepperPizza三个类和上述类似
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    // OrderPizza.java
    public abstract class OrderPizza {
        // 定义一个抽象方法, 让各个工厂子类自己实现
        abstract Pizza createPizza(String orderType);
        
        public OrderPizza() {
            Pizza pizza = null;
            String orderType;  // 订购披萨的类型
            do {
                orderType = getType();
                pizza = createPizza(orderType); //抽象方法,由工厂子类完成
                //输出pizza 制作过程
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
    
            } while (true);
        }
        
    	...getType()...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    // LDOrderPizza.java
    public class LDOrderPizza extends OrderPizza {
        @Override
        Pizza createPizza(String orderType) {
    
            Pizza pizza = null;
            if (orderType.equals("cheese")) {
                pizza = new LDCheesePizza();
            } else if (orderType.equals("pepper")) {
                pizza = new LDPepperPizza();
            }
            return pizza;
        }
    }
    // BJOrderPizza和上述类似
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    // 相当于一个客户端,发出订购 
    public class PizzaStore {
        public static void main(String[] args) {
            String loc = "bj";
            if (loc.equals("bj")) {
                // 先进入到父类OrderPizza的构造方法
                // 在构造方法中执行到createPizza方法时调用的是子类BJOrderPizza重写的方法(多态)
                new BJOrderPizza();  // 创建北京口味的各种Pizza
            } else {
                new LDOrderPizza();  // 创建伦敦口味的各种Pizza
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.抽象工厂模式

    4.1 特点

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

    • 将简单工厂模式和工厂方法模式进行整合

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

    • 将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展

    4.2 类图

    在这里插入图片描述

    4.3 代码实现

    // 抽象工厂模式的抽象层
    public interface AbsFactory {
        // 让工厂子类具体实现
        public Pizza createPizza(String orderType);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    // 工厂子类
    public class BJFactory implements AbsFactory {
        @Override
        public Pizza createPizza(String orderType) {
            Pizza pizza = null;
            if (orderType.equals("cheese")) {
                pizza = new BJCheesePizza();
            } else if (orderType.equals("pepper")) {
                pizza = new BJPepperPizza();
            }
            return pizza;
        }
    }
    // LDFactory.java类似
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    public class OrderPizza {
    
        AbsFactory factory;
        // 构造器
        public OrderPizza(AbsFactory factory) {
            setFactory(factory);
        }
    
        private void setFactory(AbsFactory factory) {
            Pizza pizza = null;
            String orderType;
            this.factory = factory;
            do {
                orderType = getType();
                // factory可能是北京的工厂子类,也可能是伦敦的工厂子类
                pizza = factory.createPizza(orderType);
                if (pizza != null) {
                    pizza.prepare();
                    pizza.bake();
                    pizza.cut();
                    pizza.box();
                } else {
                    System.out.println("订购失败");
                    break;
                }
            } while (true);
        }
        
    	...getType()...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    // 相当于一个客户端,发出订购 
    public class PizzaStore {
        public static void main(String[] args) {
            //new OrderPizza(new BJFactory());
            new OrderPizza(new LDFactory());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5.总结

    • 工厂模式的意义:将实例化对象的代码提取出来,放到一个类中统一管理和维护

    • 记住有哪三种工厂模式


    6.参考

    https://www.bilibili.com/video/BV1G4411c7N4?p=39-48


  • 相关阅读:
    RabbitMQ 部署方式选择
    (附源码)springboot大学生创新创业管理 毕业设计 041557
    C#控制电脑注销、关机、重启
    34、Java 中有了基本数据类型,为什么还需要有包装类型?包装类型是啥?
    投影仪假1080P和真1080P的差别,4000元价位真1080P投影仪推荐
    智慧驿站:为城市带来全新智慧公厕未来形态
    接口性能调优的方法,这有11种,你知道几种?
    java框架常见的面试题
    Flink-JDBC SQL Connector报错: java.lang.Integer cannot be cast to java.lang.Long
    【Spring源码系列】Bean生命周期-依赖注入
  • 原文地址:https://blog.csdn.net/qq_41398418/article/details/125566376