设计模式(二)之创建型模式--工厂模式

工厂模式

作用:实现了创建者和调用者的分离

核心本质:

​ 1、实例化对象不使用new,用工厂方法代替

​ 2、将选择实现类,创建对象统一管理和控制。从而将调用者和实现类解耦

详细分类:

​ 1、简单工厂模式

​ 2、工厂方法模式

​ 3、抽象工厂模式

需满足的OOP七大原则:

​ 1、开闭原则:对扩展开放,对修改关闭

​ 2、依赖倒转原则:接口编程,非实现编程

​ 3、迪米特原则:只与你直接的朋友通信,而避免与陌生人通信

一、简单工厂模式

1、代码实例

以生产车为实例,进行代码程度理解

1.1 初始new方式实例化对象

总结:

​ 开发层面:接口—>实现—>调用者

image-20210615221046047

1.1.1 接口类:Car类
1
2
3
public interface Car {
void name();
}
1.1.2 实现类

(1)实现类:五菱宏光

1
2
3
4
5
6
7
public class WuLing implements  Car{

@Override//重写接口类的方法
public void name() {
System.out.println("五菱宏光!");
}
}

(2)实现类:特斯拉

1
2
3
4
5
6
7
public class Tesla implements  Car{

@Override//重写接口类的方法
public void name() {
System.out.println("特斯拉!");
}
}
1.1.3 调用者—Consumer
1
2
3
4
5
6
7
8
9
10
public class Consumer {
public static void main(String[] args) {
//方法一:接口,需要了解所有的实现类
Car car = new WuLing();
Car car1 = new Tesla();

car.name();
car1.name();
}
}

结果:

1
2
五菱宏光!
特斯拉!

分析:

​ new方法的接口,需要了解所有的实现类

缺点:需要了解实现类的所有细节

1.2 factory方法实例化对象

1.1的基础之上进行一定程度的修改

总结:

​ 开发层面:接口—>实现—>工厂类—>调用者

image-20210615221112255

(1)添加工厂类:CarFactory

1
2
3
4
5
6
7
8
9
10
11
12
public class CarFactory {
public static Car getCar(String car){
if(car.equals("五菱")){
return new WuLing();
}
else if(car.equals("特斯拉")){
return new Tesla();
}else {
return null;
}
}
}

(2)修改Consumer类

1
2
3
4
5
6
7
8
9
10
public class Consumer {
public static void main(String[] args) {
//方法二:使用工厂创建
Car car = CarFactory.getCar("五菱");
Car car1 = CarFactory.getCar("特斯拉");

car.name();
car1.name();
}
}

结果:

1
2
五菱宏光!
特斯拉!

分析:

使用工厂类方法获取实例,调用者无需关心其具体的实现细节

​ 相比较于new方式:在实现类的基础之上继续封装,通过创建工厂来完成其封装,在工厂类中实现new的方式,而调用者在调用过程中,直接跟工厂说明具体的品牌即可,而无需去关心其创建的细节

缺点:若想新增一个实现类,则需要在CarFactory类(工厂类)中继续添加一个else if,其不满足OOP七大原则中的开闭原则

​ 比如:新增大众品牌

​ (1)大众实现类:

1
2
3
4
5
6
7
public class Dazhong implements Car {

@Override
public void name() {
System.out.println("大众!");
}
}

​ (2)修改工厂CarFactory类:违反了开闭原则

1
2
3
4
5
6
7
8
9
10
11
12
13
public class carFactory {
public static Car getCar(String car){
if(car.equals("五菱")){
return new Wuling();
}else if(car.equals("特斯拉")){
return new Tesla();
}else if(car.equals("大众")){//需要在代码中添加一个逻辑判断
return new Dazhong();
}else {
return null;
}
}
}

​ (3)进一步修改工厂CarFactory类,满足开闭原则

​ 上一步(2)的方式对方法进行了修改,违反开闭原则,因此,我们可以采取另外一种方式,使其满足开闭原则,具体代码如下:

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 carFactory {
//方法一
public static Car getCar(String car){
if(car.equals("五菱")){
return new Wuling();
}else if(car.equals("特斯拉")){
return new Tesla();
}else if(car.equals("大众")){
return new Dazhong();
}else {
return null;
}
}
//方法二
public static Car getWuling(){
return new Wuling();
}

public static Car getTesla(){
return new Tesla();
}

}

​ 可以将方法一修改为方法二,这样在每次新增一个品牌时,只用新增一个方法功能即可。但我们希望在扩展时,该CarFactory类完全不改变。因此,该方式也不满足于我们的需求。该模式也可以称为静态工厂模式(简单工厂模式),其弊端为:增加一个新的产品,不可能不修改代码。

二、工厂方法模式

1、代码实例

以生产车为实例,进行代码程度理解

在接口类(Car)、实现类(Wuling、Tesla)的基础之上进行进一步的研究

总结:

​ 开发层面:接口—>实现—>工厂接口—>工厂实现—>调用者

image-20210615221130141

1.1 接口类:Car类

代码同简单工厂模式中的接口类一致

1.2 实现类

(1)实现类:五菱宏光

(2)实现类:特斯拉

代码同简单工厂模式中对应的实现类一致

1.3 接口类:工厂接口类:carFactory类

创建一个汽车的工厂接口类

1
2
3
>public interface carFactory {
Car getCar();
>}

1.4 实现类:工厂接口的实现类

(1)WulingFactory类

1
2
3
4
5
6
public class WulingFactory implements carFactory {
@Override
public Car getCar() {
return new Wuling();
}
}

(2)TeslaFactory类

1
2
3
4
5
6
public class TeslaFactory implements carFactory {
@Override
public Car getCar() {
return new Tesla();
}
}

1.5 调用者—Consumer

1
2
3
4
5
6
7
8
9
10
public class Consumer {
public static void main(String[] args) {
//需要注意这里的new方法与new实例化对象的区别
Car car = new WulingFactory().getCar();
Car car1 = new TeslaFactory().getCar();

car.name();
car1.name();
}
}

分析:

​ Car car = new WulingFactory().getCar(); 也用到了new方式,为什么不直接使用new创建?

理由:

​ 假设汽车是由发动机、轮胎和底盘组成,则直接使用new方式实例化对象时, 需要实例化发动机、轮胎和底盘,而这些汽车的组件是与调用者并无直接关系的,这就严重违反了迪米特法则,其耦合度太高,且非常不利于扩展。

​ 使用工厂方法模式。其调用者的耦合度大大降低,这对于工厂来说,是可以扩展的,如果以后想组装其他的汽车,只需要新增加一个Car接口类的实现类和一个工厂接口类的实现类即可,无需对直接的代码做任何的更改。

简单工厂模式VS工厂方法模式

(1)结构复杂度:简单工厂模式最佳

(2)代码复杂度:简单工厂模式最佳

(3)编程复杂度:简单工厂模式最佳

(4)管理复杂度:简单工厂模式最佳

(5)根据实际原则:采用工厂方法模式

(6)根据实际业务:采用简单工厂模式

三、抽象工厂模式

定义:抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定他们的类。

适用场景:

​ 1、客户端(应用层)不依赖于产品类实例如何被创建、实现等细节

​ 2、强调一系列相关的产品对象(属于同一产品簇),一起使用创建对象需要大量的重复代码

​ 3、提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户极端不依赖于具体的实现

1、应用实例

以手机和路由器为实例

产品等级结构:小米手机和华为手机,都是手机的产品制造商,因此,可以称为同一个产品等级结构

产品簇:小米手机和小米路由器,都由小米公司来制造,因此属于同一个产品簇

总结:所有同一个产品簇中的产品都是由同一个工厂来生产的,但却属于不同的产品等级结构。

image-20210613124146486

2、代码实例

2.1 产品接口类

2.1.1 手机产品接口类—IphoneProduct
1
2
3
4
5
6
7
//手机产品接口
public interface IphoneProduct {
void start();//开机
void shutdown();//关机
void callup();//打电话
void sendSms();//发短信
}
2.1.2 路由器产品接口类— IRouterProduct
1
2
3
4
5
6
7
//路由器产品接口
public interface IRouterProduct {
void start();//开机
void shutdown();//关机
void openwifi();//打开wifi
void setting();//设置
}

2.2 产品接口类的实现

2.2.1 手机接口实现—小米手机—Xiaomi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//小米手机
public class XiaomiPhone implements IphoneProduct{
@Override
public void start() {
System.out.println("开启小米手机!");
}

@Override
public void shutdown() {
System.out.println("关闭小米手机!");
}

@Override
public void callup() {
System.out.println("小米打电话!");
}

@Override
public void sendSms() {
System.out.println("小米发短信!");
}
}
2.2.2 手机接口实现—华为手机—Huawei
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//华为手机
public class HuaweiPhone implements IphoneProduct{
@Override
public void start() {
System.out.println("开启华为手机!");
}

@Override
public void shutdown() {
System.out.println("关闭华为手机!");
}

@Override
public void callup() {
System.out.println("华为打电话!");
}

@Override
public void sendSms() {
System.out.println("华为发短信!");
}
}
2.2.3 路由器接口实现—小米路由器—Xiaomi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//小米路由器
public class XiaomiRouter implements IRouterProduct {
@Override
public void start() {
System.out.println("启动小米路由器");
}

@Override
public void shutdown() {
System.out.println("关闭小米路由器");
}

@Override
public void openwifi() {
System.out.println("打开小米wifi");
}

@Override
public void setting() {
System.out.println("小米设置");
}
}
2.2.4 路由器接口实现—华为路由器—Huawei
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//华为路由器
public class HuaweiRouter implements IRouterProduct {
@Override
public void start() {
System.out.println("启动华为路由器");
}

@Override
public void shutdown() {
System.out.println("关闭华为路由器");
}

@Override
public void openwifi() {
System.out.println("打开华为wifi");
}

@Override
public void setting() {
System.out.println("华为设置");
}
}

2.3 工厂的接口类—产品接口的接口—IProductFactory

1
2
3
4
5
6
7
public interface IProductFactory {
//生产手机
IphoneProduct iphoneProduct();

//生产路由器
IRouterProduct routerProduct();
}

2.4 工厂接口类的实现

2.4.1 小米工厂类—XiaomiFactory
1
2
3
4
5
6
7
8
9
10
11
public class XiaomiFactory implements  IProductFactory {
@Override
public IphoneProduct iphoneProduct() {
return new XiaomiPhone();
}

@Override
public IRouterProduct routerProduct() {
return new XiaomiRouter();
}
}
2.4.2 华为工厂类—HuaweiFactory
1
2
3
4
5
6
7
8
9
10
11
public class HuaweiFactory implements  IProductFactory {
@Override
public IphoneProduct iphoneProduct() {
return new HuaweiPhone();
}

@Override
public IRouterProduct routerProduct() {
return new HuaweiRouter();
}
}

2.5 客户端调用—client类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class client {
public static void main(String[] args) {
System.out.println("==============小米系列产品===============");
//小米工厂
XiaomiFactory xiaomiFactory = new XiaomiFactory();
IphoneProduct iphoneProduct = xiaomiFactory.iphoneProduct();
iphoneProduct.callup();
iphoneProduct.sendSms();

IRouterProduct iRouterProduct = xiaomiFactory.routerProduct();
iRouterProduct.openwifi();

System.out.println("==============华为系列产品===============");
HuaweiFactory huaweiFactory= new HuaweiFactory();
iphoneProduct = huaweiFactory.iphoneProduct();
iphoneProduct.start();
iphoneProduct.callup();

iRouterProduct = huaweiFactory.routerProduct();
iRouterProduct.setting();
}
}

结果:

==============小米系列产品===============

小米打电话!

小米发短信!

打开小米wifi

==============华为系列产品===============

开启华为手机!

华为打电话!

华为设置

四、三者区别

简单工厂:用来生产同一等级结构中的任意产品(对于增加新的产品,无能为力)

工厂方法:用来生产同一登记结构中的固定产品(支持增加任意产品)

抽象工厂:用来生产不同产品簇的全部产品(对于增加新的产品,无能为力;支持增加产品簇)

0%