旧日堂前燕,和烟雨,又双飞。人自老,春长好,梦佳期。

——韩元吉《六州歌头》

[TOC]

设计模式-工厂模式

工厂模式适合场景:

  • 如果你和你对象去饭馆吃饭,如果没有服务员(工厂类),点菜怎么点?

  • 餐馆的菜单方便客人更改吗?

  • 凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂模式进行创建。

1. 工厂模式在 JDK-Calendar 的应用

工厂方法模式

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 第一步创建Calendar对象 
Calendar calendar = Calendar.getInstance();

// 第二步调用getInstance()方法(抽象类Calendar)
public static Calendar getInstance(){
return createCalendar(
TimeZone.getDefault(),
Locale.getDefault(Locale.Category.FORMAT));
}

// 第三步创建对象
private static Calendar createCalendar(TimeZone zone,Locale aLocale){
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}

Calendar cal = null;

if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}

2. 简单工厂模式

  1. 建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
  2. 简单工厂把实例化的操作单独放到一个类中,这个类就成为简单工厂类,让简单工厂类来决定应该用哪个具体子类来实例化。
  3. 这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节。而且一旦子类发生改变,例如增加子类,那么所有的客户类都要进行修改。
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
37
38
39
40
41
42
43
44
45
46
47
48
49
//定义一个接口规范
public interface Sender {
public void Send();
}

//建造一个实现类,并且实现定义的接口
public class MailSender implements Sender{
public void Send() {
System.out.println("this is mailsender!");
}
}

//建造一个实现类,并且实现定义的接口
public class SmsSender implements Sender {
public void Send() {
System.out.println("this is sms sender!");
}


//建工厂类
public class SendFactory {
public Sender produce(String type){
if("mail".equals(type)){
return new MailSender();
}else if("sms".equals(type)){
return new SmsSender();
}else{
System.out.println("请输入正确的类型!");
return null;
}
}

}

//进行测试
public class FactoryTest {

public static void main(String[] args) {
//创建工厂类对象
SendFactory factory = new SendFactory();

//通过工厂类来创建SmsSender对象,
//SmsSender smsSender = factory.produce("sms");
Sender sender = factory.produce("sms");

//smsSender.Send();
sender.Send();
}
}

专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它又称为静态工厂方法模式。体现在下面的代码中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//创建一个工厂类
public class SendFactory {  
      
public static Sender produceMail(){  
return new MailSender();  
}  

public static Sender produceSms(){  
return new SmsSender();  
}  
}  


public class FactoryTest {  
  
public static void main(String[] args) {

Sender sender = SendFactory.produceMail(); 

sender.Send();  
}  
}  

3. 工厂方法模式(Factory Method)

  1. 在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
  2. 因为工厂方法模式把具体产品的创建推迟到工厂类的子类(具体工厂)中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开放封闭原则,克服了简单工厂模式中缺点。
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//  1. 创建抽象工厂类
abstract class Factory{
public abstract Product Manufacture();
}

// 2. 创建抽象产品类
abstract class Product{
public abstract void Show();
}

// 3. 创建具体产品类(继承抽象产品类), 定义生产的具体产品;
//具体产品A类
class ProductA extends Product{
@Override
public void Show() {
System.out.println("生产出了产品A");
}
}

//具体产品B类
class ProductB extends Product{

@Override
public void Show() {
System.out.println("生产出了产品B");
}
}
// 4. 创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
//工厂A类 - 生产A类产品
class FactoryA extends Factory{
@Override
public Product Manufactu re() {
return new ProductA();
}
}

//工厂B类 - 生产B类产品
class FactoryB extends Factory{
@Override
public Product Manufacture() {
return new ProductB();
}
}

// 5. 外界通过调用具体工厂类的方法,从而创建不同具体产品类的实
//生产工作流程
public class FactoryPattern {
public static void main(String[] args){
//客户要产品A
FactoryA mFactoryA = new FactoryA();
mFactoryA.Manufacture().Show();

//客户要产品B
FactoryB mFactoryB = new FactoryB();
mFactoryB.Manufacture().Show();
}
}

3. 抽象工厂模式(Abstract Factory)

抽象工厂模式是对工厂方法模式的进一步改进,在工厂方法模式中,工厂的核心类只能产出一种产品。而在抽象工厂模式中,可以创建一组相关联的产品。

一系列产品类

这里举两个例子:蛋糕的制作和果汁的制作;

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
*制作水果汁接口
*/
public interface JuiceProduct {
void make();
}

/**
*制作蛋糕的接口
*/
public interface CakeProduct {
void cooking();
}


/**
* 制作苹果汁
*/
public class AppleJuiceProduct implements JuiceProduct {
@Override
public void make() {
System.out.println("正在制作苹果汁>>>");
}
}
/**
* 制作梨汁
*/
public class PearJuiceProduct implements JuiceProduct {
@Override
public void make() {
System.out.println("正在制作梨汁>>>");
}
}

/**
* 制作香蕉汁
*/
public class BananaJuiceProduct implements JuiceProduct {
@Override
public void make() {
System.out.println("正在制作香蕉汁>>>");
}
}

public class CheeseCakeProduct implements CakeProduct {
@Override
public void cooking() {
System.out.println("正在烹饪芝士蛋糕>>>");
}
}

一系列工厂类
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 interface SetMealFactory {

//生产蛋糕
CakeProduct productCake();

//生产果汁
JuiceProduct productJuice();

}

/**
* A套餐生产工厂
*/
public class ASetMealFactory implements SetMealFactory{

//生产芝士蛋糕
@Override
public CakeProduct productCake() {
return new CheeseCakeProduct();
}

//生产苹果汁
@Override
public JuiceProduct productJuice() {
return new AppleJuiceProduct();
}
}

通过抽象工厂模式和工厂方法模式区别这篇博客的类图可以更通透的理解抽象工厂模式。

5. 工厂模式小结

工厂模式的意义:

  1. 将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。

三种工厂模式:

  1. 简单工厂模式
  2. 工厂方法模式
  3. 抽象工厂模式