工厂模式

工厂方法模式

工厂方法模式使用的频率非常高 ,用于创建对象的接口, 让子类决定实例化哪一个类。 工厂方法使一个类的实例化延迟到其子类 。用于封装管理对象的创建,是一种创建模式。是典型的解耦框架,在需要灵活的可扩展的框架时可以采用,可以用在异构项目中,可以使用在测试驱动的开发框架下。

工厂方法模式类图

抽象产品类,抽象人种类:

1
2
3
4
5
public interface Human {
void getColor();

void talk();
}

具体的产品类可以有多个, 都继承于抽象产品类,具体的人种类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class BlackHuman implements Human {
@Override
public void getColor() {
System.out.println("黑色人种");
}

@Override
public void talk() {
System.out.println("我是黑色人种");
}
}

public class WhiteHuman implements Human {
@Override
public void getColor() {
System.out.println("白色人种");
}

@Override
public void talk() {
System.out.println("我是白色人种");
}
}

public class YellowHuman implements Human {
@Override
public void getColor() {
System.out.println("黄色人种");
}

@Override
public void talk() {
System.out.println("我是黄色人种");
}
}

抽象工厂类负责定义产品对象的产生:

1
2
3
public abstract class AbstractHumanFactory {
public abstract <T extends Human> T createHuman(Class<T> clazz);
}

具体如何产生一个产品的对象, 是由具体的工厂类实现的,具体的工厂类:

1
2
3
4
5
6
7
8
9
10
11
public class HumanFactory extends AbstractHumanFactory {
@Override
public <T extends Human> T createHuman(Class<T> clazz) {
try {
return (T) Class.forName(clazz.getName()).newInstance();
} catch (Exception e) {
System.out.println("人种生成错误");
}
return null;
}
}

场景类的调用:

1
2
3
4
5
6
7
8
9
10
AbstractHumanFactory YinYangLu = new HumanFactory();
Human whiteHuman = YinYangLu.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
Human blackHuman = YinYangLu.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
Human yellowHuman = YinYangLu.createHuman(YellowHuman.class);
yellowHuman.getColor();
yellowHuman.talk();

优点

  • 良好的封装性, 代码结构清晰
  • 良好的扩展性,增加产品类, 只要适当地修改具体的工厂类或扩展一个工厂类
  • 屏蔽产品类,产品类的实现如何变化, 调用者都不需要关心,上层模块不发生变化
  • 典型的解耦框架,高层模块值需要知道产品的抽象类,符合迪米特法则、依赖倒置原则、里氏替换原则

使用场景

  • 需要生成对象的地方都可以使用, 但是需要慎重考虑是否要增加一个工厂类进行管理, 增加代码的复杂度
  • 需要灵活的、 可扩展的框架时
  • 异构项目中,如通过WebService与一个非Java的项目交互
  • 可以使用在测试驱动开发的框架下

扩展

工厂方法模式有很多扩展,且与其他模式结合使用威力更大,可将其缩小为简单工厂模式,可升级为多个工厂类,可替代单例模式,可延迟初始化

缩小为简单工厂模式

该模式是工厂方法模式的弱化,简单工厂模式又叫静态工厂模式,仅简单的对不同类对象的创建进行了简单的封装。缺点工厂类的扩展比较困难不符合开闭原则

简单工厂模式类图

简单工厂模式相对于工厂方法模式,去掉了AbstractHumanFactory抽象类, 同时把createHuman方法设置为静态类型, 简化了类的创建过程。

1
2
3
4
5
6
7
8
9
10
public class HumanFactory {
public static <T extends Human> T createHuman(Class<T> clazz) {
try {
return (T) Class.forName(clazz.getName()).newInstance();
} catch (Exception e) {
System.out.println("人种生成错误");
}
return null;
}
}

场景类的调用:

1
2
3
4
5
6
7
8
9
Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
Human blackHuman = HumanFactory.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
Human yellowHuman = HumanFactory.createHuman(YellowHuman.class);
yellowHuman.getColor();
yellowHuman.talk();

升级为多个工厂类

在相对比较复杂的项目中,经常遇到初始化一个对象很耗费精力的情况,所有产品类都放到一个工厂方法中进行初始化会使代码结构不清晰。为每个产品定义一个创造者, 然后由调用者自己去选择与哪个工厂方法关联。

多工厂模式的工厂抽象类,抽象方法中已经不再需要传递相关参数了, 因为每一个具体的工厂都已经非常明确自己的职责。但也给可扩展性可维护性带来了一定的影响。

多个工厂类类图

多工厂模式的抽象工厂类:

1
2
3
public abstract class AbstractHumanFactory {
public abstract Human createHuman();
}

黑色人种的创建工厂实现:

1
2
3
4
5
public class BlackHumanFactory extends AbstractHumanFactory {
public Human createHuman() {
return new BlackHuman();
}
}

黄色人种的创建工厂实现:

1
2
3
4
5
public class YellowHumanFactory extends AbstractHumanFactory {
public Human createHuman() {
return new BlackHuman();
}
}

白色人种的创建工厂实现:

1
2
3
4
5
public class WhiteHumanFactory extends AbstractHumanFactory {
public Human createHuman() {
return new BlackHuman();
}
}

场景类的调用:

1
2
3
4
5
6
7
8
9
Human whiteHuman = (new WhiteHumanFactory()).createHuman();
whiteHuman.getColor();
whiteHuman.talk();
Human blackHuman = (new BlackHumanFactory()).createHuman();
blackHuman.getColor();
blackHuman.talk();
Human yellowHuman = (new YellowHumanFactory()).createHuman();
yellowHuman.getColor();
yellowHuman.talk();

在复杂的应用中一般采用多工厂的方法, 然后再增加一个协调类, 避免调用者与各个子工厂交流, 协调类的作用是封装子工厂类, 对高层模块提供统一的访问接口。

替代单例模式

通过获得类构造器, 然后设置访问权限, 生成一个对象, 然后提供外部访问, 保证内存中的对象唯一。 通过工厂方法模式创建了一个单例对象, 该框架可以继续扩展, 在一个项目中可以产生一个单例构造器, 所有需要产生单例的类都遵循一定的规则 , 然后通过扩展该框架。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Singleton {
private Singleton() {}

public void doSomething() {}
}

public class SingletonFactory {
private static Singleton singleton;
static{
try {
Class cl= Class.forName(Singleton.class.getName());
// 获得无参构造
Constructor constructor = cl.getDeclaredConstructor();
// 设置无参构造是可访问的
constructor.setAccessible(true);
// 产生一个实例对象
singleton = (Singleton)constructor.newInstance();
} catch (Exception e) {
// 异常处理
}
}
public static Singleton getSingleton(){
return singleton;
}
}

延迟初始化

一个对象被消费完后,并不立即释放,工厂类保持其初始状态,等待再次被调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ProductFactory {
private static final Map<String, Human> humanMap = new HashMap<>();
public static synchronized Human createHuman(String type) throws Exception {
Human human;
if (humanMap.containsKey(type)) {
human = humanMap.get(type);
} else {
if (type.equals("BlackHuman")) {
human = new BlackHuman();
} else if (type.equals("WhiteHuman")) {
human = new WhiteHuman();
} else {
human = new YellowHuman();
}
humanMap.put(type, human);
}
return human;
}
}

延迟加载框架是可扩展的, 例如限制某一个产品类的最大实例化数量, 可以通过判断Map中已有的对象数量来实现,还可以用在对象初始化比较复杂的情况下, 例如硬件访问, 涉及多方面的交互, 则可以通过延迟加载降低对象的产生和销毁带来的复杂性


抽象工厂模式

抽象工厂模式是一种比较常用的模式,为创建一组相关相互依赖的对象提供一个接口, 且无须指定它们
的具体类。 当一个对象族有相同的约束时可以使用抽象工厂模式。

优点封装性,产品的具体实现细节高层模块不需要关心;产品族内的约束为非公开状态。缺点产品族扩展非常困难,严重违反开闭原则。

抽象工厂模式类图

抽象工厂模式工厂方法模式升级版, 在有多个业务品种、 业务分类时, 通过抽象工厂模式产生需要的对象是一种非常好的解决方式。

人种接口:

1
2
3
4
5
public interface Human {
void getColor();
void talk();
void getSex();
}

人种有三个抽象类, 负责人种的抽象属性定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public abstract class AbstractBlackHuman implements Human {
@Override
public void getColor() {
System.out.println("黑色人种");
}

@Override
public void talk() {
System.out.println("我是黑色人种");
}
}

public abstract class AbstractWhiteHuman implements Human {
@Override
public void getColor() {
System.out.println("白色人种");
}

@Override
public void talk() {
System.out.println("我是白色人种");
}
}

public abstract class AbstractYellowHuman implements Human {
@Override
public void getColor() {
System.out.println("黄色人种");
}

@Override
public void talk() {
System.out.println("我是黄色人种");
}
}

每个抽象类都有两个实现类, 分别实现公共的最细节、 最具体的事物:

1
2
3
4
5
6
7
8
9
10
11
12
public class FemaleYellowHuman extends AbstractYellowHuman {
@Override
public void getSex() {
System.out.println("黄种女人");
}
}
public class MaleYellowHuman extends AbstractYellowHuman {
@Override
public void getSex() {
System.out.println("黄种男人");
}
}

制造人类的抽象工厂类:

1
2
3
4
5
public interface HumanFactory {
Human createYellowHuman();
Human createWhiteHuman();
Human createBlackHuman();
}

制造男人和女人的具体工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class FemaleFactory implements HumanFactory {
@Override
public Human createYellowHuman() {
return new FemaleYellowHuman();
}

@Override
public Human createWhiteHuman() {
return new FemaleWhiteHuman();
}

@Override
public Human createBlackHuman() {
return new FemaleBlackHuman();
}
}

public class MaleFactory implements HumanFactory {
@Override
public Human createYellowHuman() {
return new MaleYellowHuman();
}

@Override
public Human createWhiteHuman() {
return new MaleWhiteHuman();
}

@Override
public Human createBlackHuman() {
return new MaleBlackHuman();
}
}

场景类的调用:

1
2
3
4
5
6
7
8
9
10
HumanFactory maleHumanFactory = new MaleFactory();
HumanFactory femaleHumanFactory = new FemaleFactory();
Human maleYellowHuman = maleHumanFactory.createYellowHuman();
Human femaleYellowHuman = femaleHumanFactory.createYellowHuman();
femaleYellowHuman.getColor();
femaleYellowHuman.talk();
femaleYellowHuman.getSex();
maleYellowHuman.getColor();
maleYellowHuman.talk();
maleYellowHuman.getSex();