• Head First设计模式(阅读笔记)-04.工厂模式


    披萨订购

    假设要完成披萨订购的功能,披萨的种类很多,比如 GreekPizzCheesePizz 等,披萨店会根据用户需要的披萨种类制作披萨,制作的流程包括prepare->bake->cut->box


    简单实现

    下面代码的实现十分简单清晰,但是如果披萨类型增加或删除,需要去修改代码,不符合开闭原则(类应该对扩展开发,对修改关闭)


    // 下面不同的pizza类型都继承了相同的父类
    Pizza orderPizza(String type){
        Pizza pizza;
        if(type.equals("cheese")){
            pizza = new CheesePizza();
        }else if(type.equals("clam")){
            pizza = new ClamPizza();
        }
        
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        
        return pizza;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    工厂模式


    简单的披萨工厂-简单工厂模式

    从上述代码可以看出,出了创建披萨对象的代码需要修改,其他代码都是不变的,所以可以将创建披萨对象的代码分离出来作为一个新对象-披萨工厂:

    • 此时orderPizza方法变为该工厂的客户,它无需知道工厂如何得到一个披萨,只关心从工厂可以得到一个披萨,并且可以调用方法对披萨进行准备、烘烤等操作
    • 并且该工厂可以有许多客户,比如制作披萨点的菜单就可以利用该工厂制作的披萨来制定价钱等

    // 简单披萨工厂
    public class SimplePizzaFactory{
        public Pizza createPizza(String type){
            Pizza pizza = null;
            if(type.equals("cheese")){
                pizza = new CheesePizza();
            }else if(type.equals("clam")){
                pizza = new ClamPizza();
            }
            return pizza;
        }
    }
    public class PizzaStore{
        SimplePizzaFactory factory;
        // 披萨店需要指定一个工厂
        public PizzaStore(SimplePizzaFactory factory){
            this.factory = factory;
        }
        public Pizza orderPizza(String type){
        	Pizza pizza;
        	factory.createPizza(type);
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
    
            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
    • 24
    • 25
    • 26
    • 27
    • 28
    加盟披萨店-工厂方法模式

    此时在纽约等地区想在当地加盟该披萨店,并且希望工厂能加工出纽约风味的披萨


    给每个地区创建一个工厂

    下面代码的缺陷在于无法让各地区的加盟店决定自己的制作流程,只是决定采用哪个工厂而已

    NYPizzaFactory nyFactory = new NYPizzaFactory();
    PizzaStore nyStore = new PizzaStore(nyFactory);
    nyStore.orderPizza("Veggie");  // 在纽约工厂制作的纽约风味披萨
    
    • 1
    • 2
    • 3
    让加盟店自己决定制作流程

    原本由一个对象负责所有具体类的实例化,现在通过子类负责实例化


    public abstract class PizzaStore{
        // orderPizza可以声明为final,防止被子类覆盖
        public Pizza orderPizza(String type){
            Pizza pizza;
            pizza = createPizza(type)  // 从createPizza方法从工厂中移到披萨店中
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
        // 定义为抽象,必须实现
        protected abstract Pizza createPizza(String type);
    }
    
    public class NYPizzaStrore extends PizzaStore{
        // 子类全权负责实例化哪个具体Pizza,父类并不知道具体创建的披萨是哪一种,只知道这个披萨要进行烘烤、切片等流程
        Pizza createPizza(String item){
            if(item.equals("chess")){
                return new NYStyleCheesePizza();
            }else if(...){
                ...
            }
        }
    }
    
    // 定义一个抽象的披萨类
    public abstract class Pizza{
        String name;
        void cut(){
            System.out.println("切成方块");
        }
    }
    
    // 纽约风味的披萨
    public class NYStyleCheesePizza extends Pizza{
        public NYStyleCheesePizza(){
            name = "NYStyle with cheese"
        }
        void cut(){
            System.out.println("切成三角形");
        }
    }
    
    // 测试
    public class Test{
        public static void main(String[] agrs){
            PizzaStore nyStore = new NYPizzaStrore();
            Pizza pizza = nyStore.orderPizza("cheese");  // nyStore决定要制作什么披萨
        }
    }
    
    • 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
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    工厂方法模式

    定义了一个创建对象的接口,由子类决定要实例化哪个类


    在这里插入图片描述

    依赖倒置原则

    对于工厂方法模式还依赖了一个原则-依赖倒置原则,该原则表示要依赖抽象,不要依赖具体类,换个说法就是高层组件和低层组件都应该依赖于抽象


    在这里插入图片描述

    使用当地原材料-抽象工厂模式

    假设不同地区的加盟店制作披萨要求用当地的原材料制作


    创建当前原料工厂

    很明显可以想到,不可能只存在一家工厂生产不同地区需要的原料,然后空运过去,可以在当地创建一个原料工厂


    // 抽象原料工厂
    public interface PizzaIngredientFactory{
        public Sauce createSauce();
        public Cheese createCheese();
    }
    // 纽约的原料工厂
    public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
        public Sauce createSauce(){
            return new NYSauce();  // 使用当前材料
        }
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    重新制作披萨

    // 抽象披萨类,将prepare方法定义为抽象了
    public abstract class Pizza{
        String name;
        Sauce sauce;
        Cheese Cheese;
        // 声明为抽象是因为现在当地披萨需要使用自己的原材料进行准备
        abstract void prepare();
        void cut(){
            System.out.println("切成方块");
        }
    }
    // 现在根据使用不同的原料工厂就可以区分出是哪个地区的CheesePizza了
    public class CheesePizza extends Pizza{
        PizzaIngredientFactory ingredientFactory;
        // 只需要传入需要地区的原料工厂即可
        public CheesePizza(PizzaIngredientFactory ingredientFactory){
            this.ingredientFactory = ingredientFactory;
        }
        void prepare(){
            // 通过传入的原料工厂就可以生产出该工程的sauce
        	sauce = ingredientFactory.createSauce();
    		...
        }
    }
    
    public class NYPizzaStore extends PizzaStore{
        Pizza createPizza(String item){
            Pizza pizza = null;
            // 纽约加盟店肯定使用纽约原料工厂了
            PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
            if(item.equals("chess")){
                // 现在不需要写为NYStyleCheesePizza,只需要传入对于原料工厂即可
                pizza = new CheesePizza(ingredientFactory);
            }else if(...){
                ...
            }
            return pizza;
        }
    }
    
    // 测试(代码没有变化)
    public class Test{
        public static void main(String[] agrs){
            PizzaStore nyStore = new NYPizzaStrore();
            Pizza pizza = nyStore.orderPizza("cheese");
        }
    }
    
    • 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
    • 43
    • 44
    • 45
    • 46
    • 47
    抽象工厂模式

    提供一个接口用于创建相关或依赖对象的家族,并且不需要明确具体类(比如在NYPizzaStorecreatePizza方法中,并没有明确具体的NYStyleCheesePizza,而是传入一个原料工厂)


    参考

    Head First 设计模式-工厂模式
    设计模式-工厂设计模式

  • 相关阅读:
    onnx-modifier使用
    RocketMQ-RocketMQ部署(Linux、docker)
    【信号与系统】信号频谱和测量之汉明窗
    gitee使用教程
    腾讯云5年服务器2核4G和4核8G配置租用价格表
    Facebook:数字时代的文化交流平台
    Android修行手册 - ConstraintLayout全属性
    脊髓型颈椎病是什么?
    智安网络|提升企业网络安全:避免成为勒索软件攻击的目标
    ASPICE标准快速掌握「2.2. 过程参考模型(Process Reference Model,PRM)」
  • 原文地址:https://blog.csdn.net/qq_41398418/article/details/128049321