设计模式之工厂模式
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.8
中Calendar
的部分代码,可以很清楚的看出,这是一个典型的简单工厂模式,根据不同参数创建不同的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
接口定义了一系列方法,可以将这些方法看成一个产品族的抽象产品。而LinkedList
、ArrayList
、HashMap
等相当于不同的具体工厂,负责各自生产其对应产品等级的产品。
网友评论