设计模式之工厂模式

2020-03-08  本文已影响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等相当于不同的具体工厂,负责各自生产其对应产品等级的产品。

上一篇下一篇

猜你喜欢

热点阅读