美文网首页
设计模式之工厂模式

设计模式之工厂模式

作者: 成为一个无趣的人 | 来源:发表于2020-03-08 14:35 被阅读0次

    设计模式之工厂模式

    1. 简单工厂模式

    1.1 模式定义

    简单工厂模式又称为静态工厂方法,它属于创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义了一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。[1]

    ​ - [1] 图说设计模式

    1.2 UML类图

    简单工程模式

    1.3 代码描述

    package com.lemon.factory.simple;
    
    /**
     * @author Hello
     * @description 抽象产品
     * @date 2020-03-07 14:06
     */
    public abstract class AbstractProduct {
        public abstract void selfIntroduce();
    }
    
    
    package com.lemon.factory.simple;
    
    /**
     * @author Hello
     * @description 具体产品A
     * @date 2020-03-07 14:10
     */
    public class ProductA extends AbstractProduct {
        @Override
        public void selfIntroduce() {
            System.out.println("I'am ProductA");
        }
    }
    
    
    package com.lemon.factory.simple;
    
    /**
     * @author Hello
     * @description
     * @date 2020-03-07 14:12
     */
    public class ProductB extends AbstractProduct {
        @Override
        public void selfIntroduce() {
            System.out.println("I'm ProductB");
        }
    }
    
    
    package com.lemon.factory.simple;
    
    /**
     * @author Hello
     * @description 产品工厂,负责根据参数创建具体产品
     * @date 2020-03-07 14:13
     */
    public class ProductFactory {
        public static AbstractProduct createProduct(String name) {
            switch (name) {
                case "A":
                    return new ProductA();
                case "B":
                    return new ProductB();
                default:
                    throw new IllegalArgumentException("该产品不存在");
            }
        }
    }
    
    

    ​ 简单工厂方法将创建对象的任务统一交给了工厂类,降低了耦合。但缺点是每新增一种产品,都需要在工厂类添加相应的case语句。为此,我们可以将工厂类做一些优化,利用反射动态创建对象,改造如下:

    package com.lemon.factory.simple;
    
    import java.util.Objects;
    
    /**
     * @author Hello
     * @description 利用反射的工厂方法
     * @date 2020-03-07 14:28
     */
    public class ReflexProductFactory {
        public static AbstractProduct createProduct(String classFullPath) {
            try {
                Class<?> clazz = Class.forName(classFullPath);
                return (AbstractProduct) clazz.newInstance();
            } catch (ClassNotFoundException | IllegalAccessException |
                    InstantiationException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        public static void main(String[] args) {
            AbstractProduct product = ReflexProductFactory.createProduct(
                    "com.lemon.factory.simple.ProductA");
            Objects.requireNonNull(product).selfIntroduce();
        }
    }
    
    

    ​ 利用反射进行改造后,新增具体产品也不用维护工厂类。但每次调用工厂方法时都必须把具体产品类的完全限定名传入,也是一件头疼的事儿。为此我们还可以进一步优化,比如将各个具体产品的完全限定名写入配置文件中,通过键取值再传入工厂方法。

    1.4 具体应用

        public static Calendar getInstance() {
            return createCalendar(TimeZone.getDefault(), Locale.getDefault(Category.FORMAT));
        }
    
        public static Calendar getInstance(TimeZone var0) {
            return createCalendar(var0, Locale.getDefault(Category.FORMAT));
        }
    
        public static Calendar getInstance(Locale var0) {
            return createCalendar(TimeZone.getDefault(), var0);
        }
    
        public static Calendar getInstance(TimeZone var0, Locale var1) {
            return createCalendar(var0, var1);
        }
    
    

    ​ 这是JDK 1.8Calendar的部分代码,可以很清楚的看出,这是一个典型的简单工厂模式,根据不同参数创建不同的Calendar实例。

    2. 工厂方法模式

    2.1 模式定义

    工厂方法模式又称工厂模式,也叫虚拟构造器模式或多态模式,它属于创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生产具体的产品对象,这样做的目的是将产品类的实例化操作延迟到子类工厂中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类[2]

    ​ - [2] 图说设计模式

    2.2 UML类图

    工厂方法模式

    2.3 代码描述

    package com.lemon.factory.method;
    
    /**
     * @author Hello
     * @description 抽象工厂
     * @date 2020-03-07 15:29
     */
    public abstract class AbstractFactory {
        public abstract AbstractProduct createProduct();
    }
    
    
    package com.lemon.factory.method;
    
    /**
     * @author Hello
     * @description 具体工厂A
     * @date 2020-03-07 15:30
     */
    public class FactoryA extends AbstractFactory{
        @Override
        public AbstractProduct createProduct() {
            return new ProductA();
        }
    }
    
    
    package com.lemon.factory.method;
    
    /**
     * @author Hello
     * @description 具体工厂B
     * @date 2020-03-07 15:30
     */
    public class FactoryB extends AbstractFactory {
        @Override
        public AbstractProduct createProduct() {
            return new ProductB();
        }
    }
    
    

    ​ 产品类代码与简单工厂相同,我就不贴出来了。若再出现新的产品,则为其添加新的工厂类即可,不用修改具体的工厂类,这样更符合“开闭原则”。

    3. 抽象工厂模式

    3.1 模式定义

    抽象工厂模式又称Kit模式,属于创建型模式。它提供了一个创建一系列相关或者相依赖对象的接口,而无需指定他们具体的类[3]

    ​ [3] 图说设计模式

    3.2 UML类图

    抽象工厂方法

    3.3 代码描述

    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 抽象工厂,具有创建产品A和产品B的抽象方法
     * @date 2020-03-07 18:52
     */
    public abstract class AbstractFactory {
        public abstract AbstractProductA createProductA();
        public abstract AbstractProductB createProductB();
    }
    
    
    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 工厂A
     * @date 2020-03-07 18:53
     */
    public class FactoryA extends AbstractFactory{
        @Override
        public AbstractProductA createProductA() {
            return new FactoryAProductA();
        }
    
        @Override
        public AbstractProductB createProductB() {
            return new FactoryAProductB();
        }
    }
    
    
    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 工厂B
     * @date 2020-03-07 18:53
     */
    public class FactoryB extends AbstractFactory {
        @Override
        public AbstractProductA createProductA() {
            return new FactoryBProductA();
        }
    
        @Override
        public AbstractProductB createProductB() {
            return new FactoryBProductB();
        }
    }
    
    
    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 抽象产品A
     * @date 2020-03-07 18:52
     */
    public abstract class AbstractProductA {
    }
    
    
    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 抽象产品B
     * @date 2020-03-07 18:53
     */
    public class AbstractProductB {
    }
    
    
    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 工厂A创建的产品A
     * @date 2020-03-07 18:53
     */
    public class FactoryAProductA extends AbstractProductA{
    }
    
    
    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 工厂A创建的产品B
     * @date 2020-03-07 18:54
     */
    public class FactoryAProductB extends AbstractProductB{
    }
    
    
    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 工厂B创建的产品A
     * @date 2020-03-07 18:54
     */
    public class FactoryBProductA extends AbstractProductA{
    }
    
    
    package com.lemon.factory.abstract1;
    
    /**
     * @author Hello
     * @description 工厂B创建的产品B
     * @date 2020-03-07 18:54
     */
    public class FactoryBProductB extends AbstractProductB{
    }
    
    

    ​ 与工厂方法相比,抽象工厂模式就是扩展了抽象工厂,使其具有创建一个产品族而不是一个产品等级的能力。当抽象工厂仅需创建一个产品等级对象时,抽象工厂也就退化成了工厂方法。

    ​ 举个栗子,某软件有两套主题。大家知道,每种主题可能会在配色、字体、按钮、图标等方面有差异,此时就很适合使用抽象工厂。我们可以将配色、字体、按钮、图标抽象成一个产品族,针对每个产品等级的元素有两种具体实现,暂且成为A和B。那么此时我们就可以定义两个具体工厂类分别封装A实现的产品族和B实现的产品族。那么该软件切换主题时就只需要切换具体工厂类就好了,是不是很方便?

    ​ 抽象工厂也有其缺点,我们还是以上述例子举例。现在该软件又有一个需求,切换主题时也要切换相应的背景图片,这时我们就需要在抽象工厂类中添加切换背景的抽象方法,自然,继承了抽象工厂类的所有具体工厂类也需要添加该方法的具体实现。

    ​ 所以抽象工厂比较适合产品族相对固定,产品等级经常改变的场景。

    3.4 具体应用

    JDK中的集合框架就是一个很好的例子,Collection接口定义了一系列方法,可以将这些方法看成一个产品族的抽象产品。而LinkedListArrayListHashMap等相当于不同的具体工厂,负责各自生产其对应产品等级的产品。

    相关文章

      网友评论

          本文标题:设计模式之工厂模式

          本文链接:https://www.haomeiwen.com/subject/lybddhtx.html