详解设计模式 - 工厂模式(3种)


这篇文章作为个人学习备忘笔记,通过生活中的牛奶工厂实例,比对3种工厂模式的不同。

工厂模式一句话总结:

只对生产结果负责,不要三无产品。

生活中的工厂例子

  • 小作坊:五花八门什么都能生产,但生产质量和产品种类不一定满足消费者的需求。
  • 专业工厂:遵循一定标准,不生产其他产品,只专注于自己的产品,不断精益求精。
  • 大型国际工厂:专业、高效,无论是产品质量还是产品种类,都能让用户放心。

以上这三种工厂,对应到设计模式中分别就是:简单工厂模式工厂方法模式抽象工厂模式

牛奶工厂案例

有三种牛奶:蒙牛、伊利、特仑苏,现在分不同的工厂去生产。

牛奶(它是一个抽象的东西)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 牛奶
*
* @author Zebe
*/
public interface Milk {

/**
* 牛奶名称
* @return 返回牛奶名称
*/
String getName();

}
蒙牛
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 蒙牛牛奶
*
* @author Zebe
*/
public class MengNiu implements Milk {

@Override
public String getName() {
return "蒙牛";
}
}
伊利
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 伊利牛奶
*
* @author Zebe
*/
public class YiLi implements Milk {

@Override
public String getName() {
return "伊利";
}
}
特仑苏
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 特仑苏牛奶
*
* @author Zebe
*/
public class TeLunSu implements Milk {

@Override
public String getName() {
return "特仑苏";
}
}

简单工厂模式的做法

用户要什么就给什么,如果自己没有的,就给不了。

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
/**
* 简单工厂(很少使用)
*
* 说明:这是简单工厂模式(根据用户要求来,不一定完全满足用户的需要)
*
* @author Zebe
*/
public class SimpleFactory {

/**
* 生产牛奶
* @param name 牛奶名称
* @return 根据牛奶名称返回具体的牛奶
*/
Milk getMilk(String name) {
if ("蒙牛".equals(name)) {
return new MengNiu();
} else if ("伊利".equals(name)) {
return new YiLi();
} else if ("特仑苏".equals(name)) {
return new TeLunSu();
} else {
// 如果要新增加一种牛奶,必须修改这里的代码实现
System.out.println("无法生成指定的牛奶:" + name);
return null;
}
}

}

使用测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 简单工厂使用测试
*
* @author Zebe
*/
public class SimpleFactoryTest {

/**
* 程序入口
* @param args 运行参数
*/
public static void main(String[] args) {
SimpleFactory factory = new SimpleFactory();
// 这里如果名称传错,会得不到想要的牛奶
System.out.println(factory.getMilk("蒙牛"));
}

}

工厂方法模式的做法

指定一个协议(标准),所有牛奶工厂都要遵循这个协议来生产。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 牛奶工厂(更加专业,不同的工厂只生产指定的牛奶)
*
* 说明:这是工厂方法模式(相当于制定一个加工协议或者标准,其他的牛奶工厂都要按照这个协议去实现)
*
* @author Zebe
*/
public interface SpecificMilkFactory {

/**
* 生产牛奶(这是一个协议)
* @return 返回牛奶
*/
Milk getMilk();

}

蒙牛工厂(按协议来生产)
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 蒙牛工厂(只专注于生产蒙牛牛奶)
*
* @author Zebe
*/
public class MengNiuFactory implements SpecificMilkFactory {

@Override
public Milk getMilk() {
return new MengNiu();
}
}
伊利工厂(按协议来生产)
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 伊利工厂(只专注于生产伊利牛奶)
*
* @author Zebe
*/
public class YiLiFactory implements SpecificMilkFactory {

@Override
public Milk getMilk() {
return new YiLi();
}
}
特仑苏工厂(按协议来生产)
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 特仑苏工厂(只专注于生产特仑苏牛奶)
*
* @author Zebe
*/
public class TeLunSuFactory implements SpecificMilkFactory {

@Override
public Milk getMilk() {
return new TeLunSu();
}
}
使用测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 牛奶工厂测试
*
* @author Zebe
*/
public class SpecificMilkFactoryTest {

/**
* 运行入口
*
* @param args 运行参数
*/
public static void main(String[] args) {
// 要什么牛奶,就需要指定具体某个专业的牛奶工厂
SpecificMilkFactory factory = new MengNiuFactory();
System.out.println(factory.getMilk());
}

}

抽象工厂模式的做法

更专业、质量更高,对于生产的产品有明确规范,除了能自己生产,还可以委派给其他专业的牛奶工厂生产(国内或者国外都行)。

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
/**
* 牛奶工厂(高级流水线工厂)
* 说明:这是抽象工厂模式(把所有能生产的牛奶抽象出来)
*
* @author Zebe
*/
public abstract class AbstractMilkFactory {

/**
* 生产蒙牛牛奶
* @return 返回蒙牛牛奶
*/
abstract Milk getMengNiu();

/**
* 生产伊利牛奶
* @return 返回伊利牛奶
*/
abstract Milk getYiLi();

/**
* 生产特仑苏牛奶
* @return 返回特仑苏牛奶
*/
abstract Milk getTeLunSu();

}

具体的某某牛奶工厂
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
/**
* 某某牛奶工厂(可以生产所有牛奶)
*
* @author Zebe
*/
public class XXXMilkFactory extends AbstractMilkFactory {

@Override
Milk getMengNiu() {
// 自己生产
return new MengNiu();
// 或委派给专业的蒙牛工厂生产(混用设计模式)
// return new MengNiuFactory().getMilk();
}

@Override
Milk getYiLi() {
// 自己生产
return new YiLi();
// 或委派给专业的伊利工厂生产(混用设计模式)
// return new YiLiFactory().getMilk();
}

@Override
Milk getTeLunSu() {
// 自己生产
return new TeLunSu();
// 或委派给专业的特仑苏工厂生产(混用设计模式)
// return new TeLunSuFactory().getMilk();
}
}
使用测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 牛奶工厂测试
*
* @author Zebe
*/
public class AbstractMilkFactoryTest {

/**
* 运行入口
*
* @param args 运行参数
*/
public static void main(String[] args) {
XXXMilkFactory factory = new XXXMilkFactory();
// 用户想要什么牛奶,应有尽有
System.out.println(factory.getMengNiu());
System.out.println(factory.getYiLi());
System.out.println(factory.getTeLunSu());
// 假设这个牛奶工厂出新产品了,例如:莫斯利安
// 那么用户只需要拿钱购买即可(客户端不做改变),如下:
// System.out.println(factory.getMoSiLiAn());
}

}

小结

1、小作坊(简单工厂模式)明显不可靠,所以很少使用或者不使用
2、工厂方法模式可以看成就是一个协议(接口),对应所有的具体工厂都要遵循这个协议来进行生产。
3、抽象工厂模式是最可靠的工厂模式,它最大程度地屏蔽了生产细节