工厂设计模式(Factory)

Posted by 余腾 on 2019-08-03
Estimated Reading Time 7 Minutes
Words 1.8k In Total
Viewed Times

什么是工厂设计模式?

工厂设计模式 —> 创建型模式

对象都需要创建,如果创建的时候直接 new 该对象,就会对该对象严重耦合

假如我们要更换对象,所有 new 对象的地方都需要修改一遍,显然违背了软件设计的开闭原则(OCP)。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;

工厂模式最大的优点就是:解耦

三种工厂设计模式的使用:

  • 1、简单工厂
  • 2、工厂方法
  • 3、抽象工厂

1、简单工厂设计模式

定义:一个工厂方法,依据传入的参数,生成对应的产品对象;

角色:

  • 1、抽象产品类

  • 2、具体产品类

  • 3、具体工厂 类

使用说明:

  • 先将产品类抽象出来,比如,苹果和梨都属于水果。
  • 抽象出来一个水果类 Fruit,苹果和梨就是具体的产品类。
  • 然后创建一个水果工厂,分别用来创建苹果和梨。


抽象水果类

1
2
3
public abstract class Fruit {
abstract void getName();
}

具体类 苹果

1
2
3
4
5
6
public class Apple extends Fruit {
@Override
public void getName() {
System.out.println("Apple");
}
}

具体类 梨

1
2
3
4
5
6
public class Pear extends Fruit {
@Override
public void getName() {
System.out.println("Pear");
}
}

水果工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
public class FruitFactory {

public Fruit createFruit(String type) {
System.out.println("======SimpleFactory======");

if (type.equals("apple")) {// 生产苹果
return new Apple();
} else if (type.equals("pear")) {// 生产梨
return new Pear();
}
return null;
}
}

简单工厂使用

1
2
3
4
5
6
7
8
9
10
public class SimpleFactory {
public static void main(String[] args) {
FruitFactory Factory = new FruitFactory();

Apple apple = (Apple) Factory.createFruit("apple");// 获得苹果
apple.getName();
Pear pear = (Pear) Factory.createFruit("pear");// 获得梨
pear.getName();
}
}
  • 一个简单工厂设计模式就完成了,但是有问题。如果我想吃香蕉,想吃橘子。这种方式,每当我想添加一种水果,就必然要修改工厂类,这显然也违反了开闭原则,亦不可取;所以简单工厂只适合于产品对象较少,且产品固定的需求,对于产品变化无常的需求来说不合适;

2、工厂方法设计模式

定义:将工厂提取成一个接口或抽象类,具体生产什么产品由子类决定。(具体工厂生产具体类

角色:

  • 1、抽象产品类
  • 2、具体产品类
  • 3、抽象工厂类
  • 4、具体工厂类

和上例中一样,产品类抽象出来,此例把工厂类也抽象出来,工厂方法模式将对象的实例化推迟到子类。


水果抽象类 苹果类和梨类 代码和上例一样

抽象工厂类

1
2
3
public abstract class FruitFactory {
public abstract Fruit createFruit();//生产水果
}

具体工厂 苹果工厂

1
2
3
4
5
6
public class AppleFactory extends FruitFactory {
@Override
public Fruit createFruit() {
return new Apple();
}
}

具体工厂 梨工厂

1
2
3
4
5
6
public class PearFactory extends FruitFactory {
@Override
public Fruit createFruit() {
return new Pear();
}
}

工厂方法使用

1
2
3
4
5
6
7
8
9
10
11
12
public class FactoryMethod {
public static void main(String[] args) {
System.out.println("======FactoryMethod======");
AppleFactory appleFactory = new AppleFactory();
PearFactory pearFactory = new PearFactory();

Apple apple = (Apple) appleFactory.createFruit();// 获得苹果
apple.getName();
Pear pear = (Pear) pearFactory.createFruit();// 获得梨
pear.getName();
}
}
  • 以上这种方式,虽然解耦了,也遵循了开闭原则,但是问题根本还是没有解决啊,换汤没换药,如果我需要的产品很多的话,需要创建非常多的工厂,所以这种方式的缺点也很明显;

3、抽象工厂设计模式

定义:为创建一组相关或者是相互依赖的对象提供的一个接口,而不需要指定它们的具体类。

角色:

  • 1、抽象产品类
  • 2、具体产品类
  • 3、抽象工厂类
  • 4、具体工厂类

抽象工厂和工厂方法的模式基本一样,区别在于,工厂方法是生产一个具体的产品,而抽象工厂可以用来生产一组相同,有相对关系的产品;重点在于一组,一批,一系列。


举个例子,假如生产 Iphone 手机,Iphone 手机有很多系列,Iphone8、IphoneXS等;假如Apple8生产需要 CPU A11的处理器,LCD屏幕,而 AppleXs 需要 CPU A12 的处理器和 OLED 屏幕;用抽象工厂来实现:

CPU 抽象类和实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class CPU {
public abstract void run();
}

public class A11 extends CPU {
@Override
public void run() {
System.out.println("A11");
}
}

public class A12 extends CPU {
@Override
public void run() {
System.out.println("A12");
}
}

屏幕 抽象类和实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Screen {
public abstract void isScreen();
}

public class LCD extends Screen {
@Override
public void isScreen() {
System.out.println("LCD");
}
}

public class OLED extends Screen {
@Override
public void isScreen() {
System.out.println("OLED");
}
}

手机工厂接口

1
2
3
4
public interface PhoneFactory {
CPU getCpu();// 使用的cpu
Screen getScreen();// 使用的屏幕
}

手机工厂实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Iphone8Factory implements PhoneFactory {
@Override
public CPU getCpu() {
return new A11();
}

@Override
public Screen getScreen() {
return new LCD();
}
}

public class IphoneXsFactory implements PhoneFactory {
@Override
public CPU getCpu() {
return new A12();
}

@Override
public Screen getScreen() {
return new OLED();
}
}

抽象工厂使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AbstractFactory {
public static void main(String[] args) {

Iphone8Factory iphone8Factory = new Iphone8Factory();
IphoneXsFactory iphoneXSFactory = new IphoneXsFactory();

System.out.println("======iphone8Factory=====");
CPU cpuA11 = iphone8Factory.getCpu();
cpuA11.run();
Screen screenLCD = iphone8Factory.getScreen();
screenLCD.isScreen();

System.out.println("======iphoneXsFactory=====");
CPU cpuA12 = iphoneXSFactory.getCpu();
cpuA12.run();
Screen screenOLED = iphoneXSFactory.getScreen();
screenOLED.isScreen();
}
}

以上例子可以看出,抽象工厂可以解决一系列的产品生产的需求,对于大批量,多系列的产品,用抽象工厂可以更好的管理和扩展;


三种工厂方式总结

  • 1、对于简单工厂和工厂方法来说,两者的使用方式实际上是一样的,如果对于产品的分类和名称是确定的,数量是相对固定的,推荐使用简单工厂模式;
  • 2、抽象工厂用来解决相对复杂的问题,适用于一系列、大批量的对象生产;

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Calendar.getInstance();

public static Calendar getInstance(){
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}

public static Locale getDefault(Locale.Category category) {
// do not synchronize this method - see 4071298
switch (category) {
case DISPLAY:
if (defaultDisplayLocale == null) {
synchronized(Locale.class) {
if (defaultDisplayLocale == null) {
defaultDisplayLocale = initDefault(category);
}
}
}
return defaultDisplayLocale;
case FORMAT:
if (defaultFormatLocale == null) {
synchronized(Locale.class) {
if (defaultFormatLocale == null) {
defaultFormatLocale = initDefault(category);
}
}
}
return defaultFormatLocale;
default:
assert false: "Unknown Category";
}
return getDefault();
}


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;
}

感谢阅读


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !