0%

设计模式之创建型模式的设计与实现

简单工厂模式

案例

​ 使用简单工厂模式模拟女娲(Nvwa)造人(Person),如果向造人的工厂方法传入参数”M“,则返回一个男人(Man)对象,如果传入参数”W“,则返回一个女人(Woman)对象,绘制相应的类图并使用 Java 语言模拟实现该场景。现需要增加一个新的机器人(Robot),如果传入参数为 “R”,则返回一个机器人对象,对代码进行修改并注意 “女娲 “类的变化。

抽象产品类

1
2
3
4
5
6
7
8
/**
* Person.java
* @author Vincent
* 抽象产品类
*/
public interface Person {
}

具体产品

1
2
3
4
5
6
7
8
9
10
11
/**
* Man.java
* @author Vincent
* 具体产品类:男人
*/
public class Man implements Person {
public Man() {
System.out.println("男人对象已创建!");
}
}

1
2
3
4
5
6
7
8
9
10
11
/**
* Woman.java
* @author Vincent
* 具体产品类:女人
*/
public class Woman implements Person {
public Woman() {
System.out.println("女人对象已创建!");
}
}

1
2
3
4
5
6
7
8
9
10
11
/**
* Robot.java
* @author Vincent
* 具体产品类:机器人
*/
public class Robot implements Person {
public Robot() {
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
/**
* Nvwa.java
* @author Vincent
* 工厂类:女娲
*/
public class Nvwa {
private static String PERSON_TYPE_MAN = "M";
private static String PERSON_TYPE_WOMAN = "W";
private static String PERSON_TYPE_ROBOT = "R";

public static Person makePerson(String type) {
if (PERSON_TYPE_MAN.equalsIgnoreCase(type)) {
System.out.println("返回一个男人对象!");
return new Man();
} else if (PERSON_TYPE_WOMAN.equalsIgnoreCase(type)) {
System.out.println("返回一个女人对象!");
return new Woman();
} else if (PERSON_TYPE_ROBOT.equalsIgnoreCase(type)) {
System.out.println("返回一个机器人对象!");
return new Robot();
}
return null;
}
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Client.java
* @author Vincent
* 客户端类
*/
public class Client {
public static void main(String[] args) {
//通过静态工厂方法创建产品
Scanner sc = new Scanner(System.in);
String type = sc.next();

//创建并获取对象
try {
Nvwa.makePerson(type);
} catch (Exception e) {
e.toString();
}
}
}

小结

角色

  • 工厂 - Nvwa

  • 抽象产品 - Person

  • 具体产品 - Man、Woman 和 Robot

特点

  • 工厂类包含必要的逻辑判断,以选择生产具体产品

  • 用于单个产品生产

优点

  • 实现了对象创建和使用的分离

  • 客户端只需要知道具体产品类对应参数,而无需知道所创建具体产品类的类名

  • 引入配置文件可在不修改任何客户端代码的情况下更换 / 增加新的具体产品类,提高了系统的灵活性

缺点

  • 工厂类职责过重

  • 增加了系统的复杂度

  • 静态工厂方法无法形成基于继承的等级结构,系统不易扩展

适用环境

  • 工厂类负责创建的对象比较少

  • 客户端不关心对象创建的细节

工厂方法模式

案例

​ 同上:使用简单工厂模式模拟女娲(Nvwa)造人(Person),如果向造人的工厂方法传入参数”M“,则返回一个男人(Man)对象,如果传入参数”W“,则返回一个女人(Woman)对象,绘制相应的类图并使用 Java 语言模拟实现该场景。现需要增加一个新的机器人(Robot),如果传入参数为 “R”,则返回一个机器人对象,对代码进行修改并注意 “女娲 “类的变化。

抽象产品类

1
2
3
4
5
6
7
8
/**
* Person.java
* @author Vincent
* 抽象产品类
*/
public interface Person {
}

具体产品

1
2
3
4
5
6
7
8
9
10
11
/**
* Man.java
* @author Vincent
* 具体产品类:男人
*/
public class Man implements Person {
public Man() {
System.out.println("男人对象已创建!");
}
}

1
2
3
4
5
6
7
8
9
10
11
/**
* Woman.java
* @author Vincent
* 具体产品类:女人
*/
public class Woman implements Person {
public Woman() {
System.out.println("女人对象已创建!");
}
}

1
2
3
4
5
6
7
8
9
10
11
/**
* Robot.java
* @author Vincent
* 具体产品类:机器人
*/
public class Robot implements Person {
public Robot() {
System.out.println("机器人对象已创建!");
}
}

抽象工厂

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Factory.java
* @author Vincent
* 抽象工厂类
*/
public interface PersonFactory {
/**
* @return 人对象
*/
Person makePerson();
}

具体工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* ManFactory.java
* @author Vincent
* 具体工厂类:男人工厂
*/
public class ManFactory implements PersonFactory {
private static String PERSON_TYPE_MAN = "M";

@Override
public Person makePerson() {
System.out.println("返回一个男人对象!");
return new Man();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* WomanFactory.java
* @author Vincent
* 具体工厂类:女人工厂
*/
public class WomanFactory implements PersonFactory {
private static String PERSON_TYPE_WOMAN = "W";

@Override
public Person makePerson() {
System.out.println("返回一个女人对象!");
return new Woman();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* RobotFactory.java
* @author Vincent
* 具体工厂类:机器人工厂
*/
public class RobotFactory implements PersonFactory {
private static String PERSON_TYPE_ROBOT = "R";

@Override
public Person makePerson() {
System.out.println("返回一个机器人对象!");
return new Robot();
}
}

客户端

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
/**
* Client.java
* @author Vincent
* 客户端类
*/
public class Client {
public static void main(String[] args) {
//通过工厂方法创建产品
Scanner sc = new Scanner(System.in);
String type = sc.next();

//创建并获取对象
PersonFactory factory = null;
switch (type) {
case "M": factory = new ManFactory(); break;
case "W": factory = new WomanFactory(); break;
case "R": factory = new RobotFactory(); break;
default:
System.out.println("输入有误!");
exit(0);
}
factory.makePerson();
}
}

小结

角色

  • 抽象产品 - Person

  • 具体产品 - Man、Woman 和 Robot

  • 抽象工厂 - PersonFactory

  • 具体工厂 - ManFactory、WomanFactory 和 RobotFactory

特点

  • 一个产品对应一个工厂类

  • 用于生产某种类型产品

优点

  • 工厂方法不仅创建客户所需要的产品,还隐藏了具体产品类的实例化细节

  • 能让工厂自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部

  • 在系统中加入新产品时,完全符合开闭原则。

缺点

  • 系统中类的个数将成对增加,增加了系统的复杂度

  • 增加了系统的抽象性

适用环境

  • 抽象工厂类通过子类来指定创建对象

  • 客户端不知道所需要对象的类

抽象工厂模式

案例

​ 一个电器工厂可以产生多种类型的电器,如海尔工厂可以生产海尔电视机、海尔空调等,TCL 工厂可以生产 TCL 电视机、TCL 空调等,相同品牌的电器构成一个产品族,而相同类型的电器构成了一个产品等级结构,现使用抽象工厂模式模拟该场景。

抽象产品类

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
/**
* AirConditioner.java
* @author Vincent
* 抽象产品类:空调
*/
public interface AirConditioner {
/**
* 开启
*/
public void on();

/**
* 关闭
*/
public void off();

/**
* 调节室温
*/
public void changeTemperature();

/**
* 调节风速
*/
public void changeBlowingSpeed();
}

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
/**
* Television.java
* @author Vincent
* 抽象产品类:电视
*/
public interface Television {
/**
* 开启
*/
public void on();

/**
* 关闭
*/
public void off();

/**
* 切换频道
*/
public void switchChannel();

/**
* 调节音量
*/
public void changeVolume();
}

具体产品

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
/**
* HaierAirConditioner.java
* @author Vincent
* 具体产品类:海尔空调
*/
public class HaierAirConditioner implements AirConditioner {
@Override
public void on() {
System.out.println("海尔空调已启动");
}

@Override
public void off() {
System.out.println("海尔空调已关闭");
}

@Override
public void changeTemperature() {
System.out.println("您正在使用海尔空调调节室温");
}

@Override
public void changeBlowingSpeed() {
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
/**
* HaierTelevision.java
* @author Vincent
* 具体产品类:海尔电视
*/
public class HaierTelevision implements Television {
@Override
public void on() {
System.out.println("海尔电视已启动");
}

@Override
public void off() {
System.out.println("海尔电视已关闭");
}

@Override
public void switchChannel() {
System.out.println("您正在海尔电视切换频道");
}

@Override
public void changeVolume() {
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
/**
* TCLAirConditioner.java
* @author Vincent
* 具体产品类:TCL空调
*/
public class TCLAirConditioner implements AirConditioner {
@Override
public void on() {
System.out.println("TCL空调已启动");
}

@Override
public void off() {
System.out.println("TCL空调已关闭");
}

@Override
public void changeTemperature() {
System.out.println("您正在使用TCL空调调节室温");
}

@Override
public void changeBlowingSpeed() {
System.out.println("您正在使用TCL空调调节风速");
}
}

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
/**
* TCLTelevision.java
* @author Vincent
* 具体产品类:TCL电视
*/
public class TCLTelevison implements Television {
@Override
public void on() {
System.out.println("TCL电视已启动");
}

@Override
public void off() {
System.out.println("TCL电视已关闭");
}

@Override
public void switchChannel() {
System.out.println("您正在使用TCL电视切换频道");
}

@Override
public void changeVolume() {
System.out.println("您正在使用TCL电视调节音量");
}
}

抽象工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Factory.java
* @author Vincent
* 抽象工厂类
*/
public interface Factory {
/**
* 返回一台空调
* @return AirConditioner
*/
public AirConditioner produceAirConditioner();

/**
* 返回一台电视
* @return Television
*/
public Television produceTelevision();
}

具体工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* HaierFactory.java
* @author Vincent
* 具体工厂类:Haier工厂
*/
public class HaierFactory implements Factory {
@Override
public AirConditioner produceAirConditioner() {
return new HaierAirConditioner();
}

@Override
public Television produceTelevision() {
return new HaierTelevision();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* TCLFactory.java
* @author Vincent
* 具体工厂类:TCL工厂
*/
public class TCLFactory implements Factory {
@Override
public AirConditioner produceAirConditioner() {
return new TCLAirConditioner();
}

@Override
public Television produceTelevision() {
return new TCLTelevison();
}
}

客户端

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
/**
* Client.java
* @author Vincent
* 客户端类
*/
public class Client {
public static void main(String[] args) {
// 使用抽象层定义
Factory factory = null;
AirConditioner airConditioner;
Television television;

// 获取具体工厂对象
try {
factory = (HaierFactory)XMLUtil.getBean();
} catch (Exception e) {
e.toString();
}

// 获取具体产品对象
airConditioner = factory.produceAirConditioner();
television = factory.produceTelevision();

// 调用具体产品方法
airConditioner.on();
airConditioner.changeTemperature();
airConditioner.changeBlowingSpeed();
airConditioner.off();
System.out.println("----------------------");
television.on();
television.switchChannel();
television.changeVolume();
television.off();
}
}

小结

角色

  • 抽象产品 - Television、AirConditioner

  • 具体产品 - Haier、TCL 对应产品族

  • 抽象工厂 - 创建 Television、AirConditioner 产品等级结构

  • 具体工厂 - Factory

特点

  • 用于生产一系列产品

优点

  • 隔离了具体类的生成

  • 当同产品族中多个对象一起工作时,能保证客户端始终只使用同一个产品族中的对象

  • 增加新的产品族无须修改已有系统,符合开闭原则

缺点

  • 又违背了开闭原则:不易增添新的产品等级结构,需要对原有系统进行较大的修改

适用环境

  • 每次只使用某一产品族

  • 同产品族产品一起使用

  • 产品等级结构稳定