[Java]设计模式之工厂模式

什么是设计模式

设计模式(Design pattern)是一套被反复使用、多数人知晓的,经过分类编目的、代码设计经验的总结。

工厂模式的概念

  • 实例化对象,用工厂方法代替 new 操作
  • 工厂模式包括工厂方法模式和抽象工厂模式
  • 抽象工厂模式是工厂方法模式的扩展

Spring 框架采用了这种设计模式。

工厂模式的意图

定义一个接口来创建对象,但是让子类来决定哪些类需要被实例化。
工厂方法把实例化的工作推迟到子类中去实现。

什么情况下适合工厂模式?

  • 有一组类似的对象需要创建
  • 在编码时不能预见需要创建哪种类的实例
  • 系统需要考虑扩展性,不依赖于产品类实例如何被创建、组合和表达的细节(低耦合)

简单工厂

先来直接代码示例吧~

先建一个接口

1
2
3
4
5
6
7
8
9
10
package com.doity.factory.simple;

/**
* Created by ARNO on 2016/4/22/022.
* desc: office的接口
*/
public interface OfficeInterface {

public void UseOffice();
}

来建两个实体

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.doity.factory.simple;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class Word implements OfficeInterface {
private static final String TAG = "Word";

public void UseOffice() {
System.out.println("正在使用 Word");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.doity.factory.simple;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class PowerPoint implements OfficeInterface {
private static final String TAG = "PowerPoint";

public void UseOffice() {
System.out.println("正在使用 PowerPoint");
}
}

建一个测试类,开始测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.doity.factory.simple;

/**
* Created by ARNO on 2016/4/22/022.
* desc: office的测试类
*/
public class TestOffice {
private static final String TAG = "TestOffice";

public static void main(String[] args) {

//常规写法
// Word word = new Word();
// PowerPoint powerPoint = new PowerPoint();
// word.UseOffice();
// powerPoint.UseOffice();

//工厂模式写法
OfficeFactory officeFactory = new OfficeFactory();
OfficeInterface word = officeFactory.getOfficeByClass("com.doity.factory.simple.Word");
word.UseOffice();
}
}

运行结果

1
正在使用 Word

抽象工厂模式

工厂模式这种设计方式非常棒,但是简单工厂这种方式适用场景还是比较狭窄的,所以产生了成抽象工厂模式。

简单工厂的模型图

简单工厂

抽象工厂的模型图

抽象工厂

抽象工厂代码示例

先来建立一个男孩接口,以及深圳男孩、上海男孩的实体类。

1
2
3
4
5
6
7
8
9
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc: 男孩的接口
*/
public interface Boy {
public void drawBoy();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class ShanghaiBoy implements Girl {
private static final String TAG = "ShanghaiBoy";

public void drawGirl() {
System.out.println("我是上海男孩");
}
}
1
2
3
4
5
6
7
8
9
10
11
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class ShenzhenBoy implements Boy{
public void drawBoy() {
System.out.println("我是深圳男生");
}
}

先来建立一个女孩接口,以及深圳女孩、上海女孩的实体类。

1
2
3
4
5
6
7
8
9
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public interface Girl {
public void drawGirl();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class ShanghaiGirl implements Girl {
private static final String TAG = "ShanghaiGirl";

public void drawGirl() {
System.out.println("我是上海女孩");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class ShenzhenGirl implements Girl{
private static final String TAG = "ShenzhenGirl";

public void drawGirl() {
System.out.println("我是深圳女生");
}
}

工厂的接口

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public interface PersonFactoryInterface {

//男孩接口
public Boy getBoy();
//女孩接口
public Girl getGirl();
}

深圳工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class ShenzhenFactory implements PersonFactoryInterface {
private static final String TAG = "ShenzhenFactory";

public Boy getBoy() {
return new ShenzhenBoy();
}

public Girl getGirl() {
return new ShenzhenGirl();
}
}

上海工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class ShanghaiFactory implements PersonFactoryInterface {
private static final String TAG = "ShanghaiFactory";

public Boy getBoy() {
return new ShenzhenBoy();
}

public Girl getGirl() {
return new ShanghaiGirl();
}
}

最后是测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.doity.factory.AbstractFactory;

/**
* Created by ARNO on 2016/4/22/022.
* desc:
*/
public class TestAbstractFactory {
private static final String TAG = "TestAbstractFactory";

public static void main(String[] args) {
PersonFactoryInterface personFactory = new ShenzhenFactory();
personFactory.getBoy().drawBoy();
}
}

运行结果

1
我是深圳男生

工厂方法模式和抽象工厂模式对比

  • 工厂模式是一种极端情况的抽象工厂模式,而抽象工厂模式可以看成是工厂模式的推广
  • 工厂模式用来创建一个产品的等级结果,而抽象工厂模式是用来创建多个产品的等级结构
  • 工厂模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类

工厂模式的实现帮助我们

  • 系统可以在不修改具体工厂角色的情况下引进新的产品
  • 客户端不必关心对象如果创建,明确了职责
  • 更好的理解面向对象的原则————面向接口编程,而不要面向实现编程

工厂模式适用于哪些场景

  • 一个系统应当不依赖产品类实例被创立、组成和表示的细节,这对于所有形态的工厂模式都是重要的
  • 这个系统的产品有至少一个的产品族
  • 同属于同一个产品族的产品是设计成在一起使用的,这一约束必须得在系统的设计中体现出来
  • 不同的产品以一系列的接口的面貌出现,从而使系统不依赖于接口实现的细节

工厂模式的局限性

  • 重构已经存在的类会破坏客户端代码
  • 因为工厂方法所实例化的类具有私有的构造方法,所- 以这些类就不能扩展了。
  • 如果确实扩展了工厂方法所实例化的类(例如将构造方法设为保护的,虽然有风险但也是可行的),子类必须具有所有工厂方法的一套实现。

小结

无论如何使用工厂,我们只关心是否降低耦合度。

参考资料