• 工厂方法模式与抽象工厂模式讲解


    看来韩顺平老师授课视频,觉得例子讲的较为形象,于是坐下总结,目的是怕自己忘记。

    背景:比如现在有披萨的一个项目:

    披萨的种类非常多(LondonPizza伦敦的, BeijingPizza北京的), 不同类别披萨下面还有不同口味(奶酪的,胡椒的)的披萨。披萨的制作过程有比如prepare, bake, cut, box 等。

    由于简单工厂模式较为简单和容易理解,所以掠过。即一个SimpleFactory类的一个静态方法根据接收的条件,创建出对应的子类对象。

    先讲解工厂方法模式:

    思考一:仍然使用简单工厂模式 ,但是这么多披萨杂在一起,显得层次十分不清晰。

    解决:引入一种更好的方法,工厂方法模式。定义了一个创建对象的抽象方法,由子类决定要实例化的类,工厂方法将对象的实例化推迟到子类(就是下面具体的订餐类)。

    步骤:

    1.创建不同的披萨,这些披萨明显需要实现一个接口或继承一个抽象类。

    2.需要一个订餐类,但是这个订餐类只提供一个创建pizza对象的抽象方法。

    3.不同类别的订餐子类分别实现这个方法,进行对象创建。

     区别:与简单工厂不一样的地方就是,这边对不同的订餐进行了分类,不同类别的订餐子类进行对象的实例化。将对象的实例化推迟到特定的订餐子类。

    所以用工厂方法来实现的话,关系图如下:

    与简单工厂不同的是,这边的BJOrderPizza、LDOrderPizza相当于简单工厂中的SimpleFactory(我这边只是名字取的不够标准,比较场景化,BJOrderPizza、LDOrderPizza虽然没有工厂相关的字眼,但是确实是相当于SimpleFactory简单工厂)。我这边只是在OrderPizza提供一个抽象创建的方法,让更具体的子类BJOrderPizza、LDOrderPizza去创建具体类型的披萨,其实就是不同类型的工厂去创建不同类型的披萨,如果(BJOrderPizza、LDOrderPizza、OrderPizza)=>替换成 SimpleFactory,其实就变成了简单工厂模式。所以工厂方法的实质是将对象的实例化推迟到特定的子类进行。(注:如果是简单工厂的话,在OrderPizza中createPizza方法马上就要返回某个具体的披萨对象,且不能再设置成抽象方法了)。

     所以根据上面的关系图把代码实现如下:

     Pizza抽象类:

    public class PizzaStore {
        public static void main(String[] args) {
            //创建北京奶酪披萨
            BJOrderPizza bjOrderPizza = new BJOrderPizza();
            Pizza cheese = bjOrderPizza.createPizza("cheese");
            cheese.pizzaShow();
            //创建伦敦的胡椒披萨
            LDOrderPizza ldOrderPizza = new LDOrderPizza();
            Pizza pepper = ldOrderPizza.createPizza("pepper");
            pepper.pizzaShow();
        }
    }

     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("北京的胡椒披萨准备原材料");
        }
    
    }

    LDCheesePizza

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

    LDPepperPizza

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

    OrderPizza

    public abstract class OrderPizza {
        abstract Pizza createPizza(String orderType);
    }

    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;
        }
    }

    LDOrderPizza

    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;
        }
    }

    PizzaStore

    public class PizzaStore {
        public static void main(String[] args) {
            //创建北京奶酪披萨
            BJOrderPizza bjOrderPizza = new BJOrderPizza();
            Pizza cheese = bjOrderPizza.createPizza("cheese");
            cheese.pizzaShow();
            //创建伦敦的胡椒披萨
            LDOrderPizza ldOrderPizza = new LDOrderPizza();
            Pizza pepper = ldOrderPizza.createPizza("pepper");
            pepper.pizzaShow();
        }
    }

     输出:

    北京的奶酪披萨准备原材料
    北京奶酪披萨baking
    北京奶酪披萨cutting
    北京奶酪披萨boxing
    ~~~结束!
    伦敦的胡椒披萨准备原材料
    伦敦胡椒披萨baking
    伦敦胡椒披萨cutting
    伦敦胡椒披萨boxing
    ~~~结束!

    接下来讲解抽象工厂模式:

    还是这个案例,抽象工厂模式的关系图,如下:

    抽象工厂模式将工厂抽象成两层。AbsFactory(抽象工厂)和具体的工厂子类。可以根据创建对象的类型选择对应的工厂子类。就将当个的简单工厂类变成了工厂簇。有利于代码的维护和拓展。(这个是面向接口编程的独到优势)。so, 抽象工厂可以看作是简单工厂和工厂方法模式的整合。这种整合并不是单纯的代码叠加,是一种思想的体现。例如关系图BJFactory和LDFactory就相当于简单工厂模式中的工厂实例。AbsFactory和BJFactory、LDFactory的关系就是类似于工厂方法模式中体现的功能下沉,将对象的实例化推迟到子类。最终这个AbsFactory聚合到一个订餐类中,传递依赖后,供使用。

    根据上面的关系图, 代码实现如下:

    其中:Pizza、BJCheesePizza、BJPepperPizza、LDCheesePizza、LDPepperPizza跟工厂方法模式是一样的,掠过。

    AbsFactory:

    public interface AbsFactory {
        public Pizza createPizza(String orderType);
    }

    BJFactory(跟工厂方法模式的BJOrderPizza内部实现是一致的):

    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(跟工厂方法模式的LDOrderPizza内部实现是一致的):

    public class LDFactory implements AbsFactory {
        @Override
        public Pizza createPizza(String orderType) {
            Pizza pizza = null;
            if(orderType.equals("cheese")){
                pizza = new LDCheesePizza();
            } else if(orderType.equals("pepper")){
                pizza = new LDPepperPizza();
            }
            return pizza;
        }
    }

    OrderPizza:

    public class OrderPizza {
        AbsFactory absFactory;
    
        public void setAbsFactory(AbsFactory absFactory) {
            this.absFactory = absFactory;
        }
    
        public Pizza getPizza(String orderType){
            return absFactory.createPizza(orderType);
        }
    }

    客户端PizzaStore:

    public class PizzaStore {
        public static void main(String[] args) {
            OrderPizza orderPizza1 = new OrderPizza();
            orderPizza1.setAbsFactory(new BJFactory());
            Pizza cheese = orderPizza1.getPizza("cheese");
            cheese.pizzaShow();
            OrderPizza orderPizza2 = new OrderPizza();
            orderPizza2.setAbsFactory(new LDFactory());
            Pizza pepper = orderPizza2.getPizza("pepper");
            pepper.pizzaShow();
        }
    }
  • 相关阅读:
    在.net中使用redis(StackExchange.Redis)
    基于windows平台的命令行软件安装工具Chocolatey的安装
    c#的日志插件NLog基本使用
    微信小程序的组件总结
    markdown语法简介
    微信小程序基础语法总结
    leetcode-mid-sorting and searching
    leetcode-mid-sorting and searching
    leetcode-mid-sorting and searching -347. Top K Frequent Elements
    leetcode-mid-sorting and searching-34 Search for a Range
  • 原文地址:https://www.cnblogs.com/chenmz1995/p/10540220.html
Copyright © 2020-2023  润新知