zoukankan      html  css  js  c++  java
  • JAVA设计模式之工厂模式—Factory Pattern

    1.工厂模式简介

    工厂模式用于对象的创建,使得客户从具体的产品对象中被解耦。

    2.工厂模式分类

    这里以制造coffee的例子开始工厂模式设计之旅。

    我们知道coffee只是一种泛举,在点购咖啡时需要指定具体的咖啡种类:美式咖啡、卡布奇诺、拿铁等等。

    /**
     * 
     * 拿铁、美式咖啡、卡布奇诺等均为咖啡家族的一种产品
     * 咖啡则作为一种抽象概念
     * @author Lsj
     *
     */
    public abstract class Coffee {
    
        /**
         * 获取coffee名称
         * @return
         */
        public abstract String getName();
        
    }
    
    
    /**
     * 美式咖啡
     * @author Lsj
     *
     */
    public class Americano extends Coffee {
    
        @Override
        public String getName() {
            return "美式咖啡";
        }
    
    }
    
    
    /**
     * 卡布奇诺
     * @author Lsj
     *
     */
    public class Cappuccino extends Coffee {
    
        @Override
        public String getName() {
            return "卡布奇诺";
        }
    
    }
    
    
    /**
     * 拿铁
     * @author Lsj
     *
     */
    public class Latte extends Coffee {
    
        @Override
        public String getName() {
            return "拿铁";
        }
    
    }

    2.1 简单工厂

    简单工厂实际不能算作一种设计模式,它引入了创建者的概念,将实例化的代码从应用代码中抽离,在创建者类的静态方法中只处理创建对象的细节,后续创建的实例如需改变,只需改造创建者类即可,

    但由于使用静态方法来获取对象,使其不能在运行期间通过不同方式去动态改变创建行为,因此存在一定局限性。

    /**
     * 简单工厂--用于创建不同类型的咖啡实例
     * @author Lsj
     *
     */
    public class SimpleFactory {
        
        /**
         * 通过类型获取Coffee实例对象
         * @param type 咖啡类型
         * @return
         */
        public static Coffee createInstance(String type){
            if("americano".equals(type)){
                return new Americano();
            }else if("cappuccino".equals(type)){
                return new Cappuccino();
            }else if("latte".equals(type)){
                return new Latte();
            }else{
                throw new RuntimeException("type["+type+"]类型不可识别,没有匹配到可实例化的对象!");
            }
        }
        
        public static void main(String[] args) {
            Coffee latte = SimpleFactory.createInstance("latte");
            System.out.println("创建的咖啡实例为:" + latte.getName());
            Coffee cappuccino = SimpleFactory.createInstance("cappuccino");
            System.out.println("创建的咖啡实例为:" + cappuccino.getName());
        }
    
    }

    2.2 工厂方法模式

    定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到了子类。

    场景延伸:不同地区咖啡工厂受制于环境、原料等因素的影响,制造出的咖啡种类有限。中国咖啡工厂仅能制造卡布奇诺、拿铁,而美国咖啡工厂仅能制造美式咖啡、拿铁。

    /**
     * 定义一个抽象的咖啡工厂
     * @author Lsj
     */
    public abstract class CoffeeFactory {
        
        /**
         * 生产可制造的咖啡
         * @return
         */
        public abstract Coffee[] createCoffee();
    
    }
    
    
    /**
     * 中国咖啡工厂
     * @author Lsj
     *
     */
    public class ChinaCoffeeFactory extends CoffeeFactory {
    
        @Override
        public Coffee[] createCoffee() {
            // TODO Auto-generated method stub
            return new Coffee[]{new Cappuccino(), new Latte()};
        }
    
    }
    
    
    /**
     * 美国咖啡工厂
     * @author Lsj
     *
     */
    public class AmericaCoffeeFactory extends CoffeeFactory {
    
        @Override
        public Coffee[] createCoffee() {
            // TODO Auto-generated method stub
            return new Coffee[]{new Americano(), new Latte()};
        }
    
    }
    
    
    /**
     * 工厂方法测试
     * @author Lsj
     *
     */
    public class FactoryMethodTest {
    
        static void print(Coffee[] c){
            for (Coffee coffee : c) {
                System.out.println(coffee.getName());
            }
        }
        
        public static void main(String[] args) {
            CoffeeFactory chinaCoffeeFactory = new ChinaCoffeeFactory();
            Coffee[] chinaCoffees = chinaCoffeeFactory.createCoffee();
            System.out.println("中国咖啡工厂可以生产的咖啡有:");
            print(chinaCoffees);
            CoffeeFactory americaCoffeeFactory = new AmericaCoffeeFactory();
            Coffee[] americaCoffees = americaCoffeeFactory.createCoffee();
            System.out.println("美国咖啡工厂可以生产的咖啡有:");
            print(americaCoffees);
        }
    }

    2.3 抽象工厂

    提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

    在上述的场景上继续延伸:咖啡工厂做大做强,引入了新的饮品种类:茶、 碳酸饮料。中国工厂只能制造咖啡和茶,美国工厂只能制造咖啡和碳酸饮料。

    如果用上述工厂方法方式,除去对应的产品实体类还需要新增2个抽象工厂(茶制造工厂、碳酸饮料制造工厂),4个具体工厂实现。随着产品的增多,会导致类爆炸。

    所以这里引出一个概念产品家族,在此例子中,不同的饮品就组成我们的饮品家族, 饮品家族开始承担创建者的责任,负责制造不同的产品。

    /**
     * 抽象的饮料产品家族制造工厂
     * @author Lsj
     *
     */
    public interface AbstractDrinksFactory {
    
        /**
         * 制造咖啡
         * @return
         */
        Coffee createCoffee();
        
        /**
         * 制造茶
         * @return
         */
        Tea createTea();
        
        /**
         * 制造碳酸饮料
         * @return
         */
        Sodas createSodas();
    }
    
    
    /**
     * 中国饮品工厂
     * 制造咖啡与茶
     * @author Lsj
     *
     */
    public class ChinaDrinksFactory implements AbstractDrinksFactory {
    
        @Override
        public Coffee createCoffee() {
            // TODO Auto-generated method stub
            return new Latte();
        }
    
        @Override
        public Tea createTea() {
            // TODO Auto-generated method stub
            return new MilkTea();
        }
    
        @Override
        public Sodas createSodas() {
            // TODO Auto-generated method stub
            return null;
        }
    
    }
    
    
    /**
     * 美国饮品制造工厂
     * 制造咖啡和碳酸饮料
     * @author Lsj
     *
     */
    public class AmericaDrinksFactory implements AbstractDrinksFactory {
    
        @Override
        public Coffee createCoffee() {
            // TODO Auto-generated method stub
            return new Latte();
        }
    
        @Override
        public Tea createTea() {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Sodas createSodas() {
            // TODO Auto-generated method stub
            return new CocaCola();
        }
    
    }
    
    
    /**
     * 抽象工厂测试类
     * @author Lsj
     *
     */
    public class AbstractFactoryTest {
        
        static void print(Drink drink){
            if(drink == null){
                System.out.println("产品:--" );
            }else{
                System.out.println("产品:" + drink.getName());
            }
        }
        
        public static void main(String[] args) {
            AbstractDrinksFactory chinaDrinksFactory = new ChinaDrinksFactory();
            Coffee coffee = chinaDrinksFactory.createCoffee();
            Tea tea = chinaDrinksFactory.createTea();
            Sodas sodas = chinaDrinksFactory.createSodas();
            System.out.println("中国饮品工厂有如下产品:");
            print(coffee);
            print(tea);
            print(sodas);
            
            AbstractDrinksFactory americaDrinksFactory = new AmericaDrinksFactory();
            coffee = americaDrinksFactory.createCoffee();
            tea = americaDrinksFactory.createTea();
            sodas = americaDrinksFactory.createSodas();
            System.out.println("美国饮品工厂有如下产品:");
            print(coffee);
            print(tea);
            print(sodas);
        }
    
    }

    3.总结

    简单工厂:不能算是真正意义上的设计模式,但可以将客户程序从具体类解耦。

    工厂方法:使用继承,把对象的创建委托给子类,由子类来实现创建方法,可以看作是抽象工厂模式中只有单一产品的情况。

    抽象工厂:使对象的创建被实现在工厂接口所暴露出来的方法中。

    工厂模式可以帮助我们针对抽象/接口编程,而不是针对具体类编程,在不同的场景下按具体情况来使用。

    参考书籍:

    《HeadFirst 设计模式》

  • 相关阅读:
    .NetCore Grpc 客服端 工厂模式配置授权
    DOCKER 拉取 dotnet 镜像太慢 docker pull mcr.microsoft.com too slow
    Introducing .NET 5
    VSCode 出现错误 System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached.
    Omnisharp VsCode Attaching to remote processes
    zookeeper3.5.5 centos7 完全分布式 搭建随记
    Hadoop2.7.7 centos7 完全分布式 配置与问题随记
    MySQL索引 索引分类 最左前缀原则 覆盖索引 索引下推 联合索引顺序
    SQL基础随记3 范式 键
    MySQL调优 优化需要考虑哪些方面
  • 原文地址:https://www.cnblogs.com/carryjack/p/7709861.html
Copyright © 2011-2022 走看看