工厂模式和单件模式

工厂模式

每次用new来实例化对象的时候,都是实例化具体的类,不是面向接口编程,而是实现;代码绑着具体类会导致代码更脆弱,更缺乏弹性,初始化也经常造成耦合的问题。

假设现在有家披萨Pizza 店,有很多披萨比如pizzaA、pizzaB、pizzaC、pizzaD,产生披萨的类一开始可能会这样写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Pizza orderPizza(String type){
// Pizza 抽象类 ABCDE 是实现子类
Pizza pizza;

if(type.equals("A")){
pizza = new pizzaA();
}else if(type.equals("B")){
pizza = new pizzaB();
}else if(type.equals("C")){
pizza = new pizzaC();
}else if(type.equals("D")){
pizza = new pizzaD();
}else if(type.equals("E")){
pizza = new pizzaE();
}

// 披萨的其他加工步骤
pizza.prepare();
pizza.bake(); //烘烤
pizza.cut(); //切片
pizza.box(); //装盒
return pizza;
}

这个设计显然违背了 封闭——开放原则,如果pizza 种类增多,或者要去除一些不受欢迎的披萨,就必须修改orderPizza ,而这都是没有对变化封闭的原因。于是我们把创建pizza 那边代码搬移到简单的工厂SimplePizzaFactory

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
36
public class SimplePizzaFactory{
public Pizza createPizza(String type){
// Pizza 抽象类 ABCDE 是实现子类
Pizza pizza = null;

if(type.equals("A")){
pizza = new pizzaA();
}else if(type.equals("B")){
pizza = new pizzaB();
}else if(type.equals("C")){
pizza = new pizzaC();
}else if(type.equals("D")){
pizza = new pizzaD();
}else if(type.equals("E")){
pizza = new pizzaE();
}

return pizza;
}
}

// 修改 orderPizza
public class PizzaStore{
SimplePizzaFactory factory;

public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
}

public Pizza orderPizza(String type){
Pizza pizza;
pizza = factory.createPizza(type);

// pizza 的其他方法
}
}

我们来看一下引入这个简单工厂的类图设计,

duck1

上面只是一个简单的工厂设计,如果披萨店变得很多了怎么办,createPizza应该生产哪家披萨店的披萨呢?我们可以把pizzaStore 设计成一个抽象类

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
public abstract Class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);

pizza.prepare();
pizza.bake();
// pizza 其他制作方法

return pizza
}

// createPiza 决定生产那个店的披萨,父类的orderPizza 和子类createPizza 解耦
abstract Pizza createPizza(String type);
}

//披萨店A
pubic class storeAPizzaStore extends PizzaStore{
Pizza createPizza(String type){
if(type.equals("A")){
return new storeApizzaA();
}else if(type.equals("B")){
return new storeApizzaB();
}else if(type.equals("C")){
return new storeApizzaC();
}else if(type.equals("D")){
return new storeApizzaD();
}
}
}

在看看工厂方法的定义

1
abstract Product factoryMethod(String type)

工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。

  • 工厂方法是抽象,依赖子类实现对象创建
  • 工厂方法必须返回一个产品
  • 工厂方法将客户代码和实际创建具体产品的代码分隔开
  • 参数看情况是否需要

这样披萨的制作过程代码就是

1
2
3
4
5
pizzaStore storeA = new storeAPizzaStore();
Pizaa storeAPizzaB = storeA.orderPizza('B');

pizzaStore storeB = new storeBPizzaStore();
Pizaa storeBPizzaB = storeB.orderPizza('B');

再来看看利用该复杂工厂的设计类图,

duck1

单件模式

在软件项目里面有些类只能有一个实例,比如线程池、缓存、对话框,日志等对象;如果制作出多个实例就会导致许多问题,比如程序的行为异常、资源使用过量,或者是不一致的结果。下面是一个经典的单件模式实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton{
private static Singleton uniqueInstance;
// 其他有用的变量

// 构造器私有
private Singleton(){
// ...
}

public static Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}

// 其他方法
}

单件模式就是,确保一个类只有一个实例,并提供一个全局访问点。但是尽管如此,如果是在多线程情况下使用的话,也有可能new 出了多个实例化对象。就是在第一次调用getInstance 创建对象时出了问题。解决多线程安全问题,一般可以这样

1
2
3
4
5
6
7
8
9
public static Synchronized Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}

// 或者在声明变量的时候 就实例化
private static Singleton uniqueInstance = new Singleton();

欢迎大家给我留言,提建议,指出错误,一起讨论学习技术的感受!

-------------本文结束感谢您的阅读-------------
Donate comment here