工厂模式
作用:实现了创建者和调用者的分离
核心本质:
1、实例化对象不使用new,用工厂方法代替
2、将选择实现类,创建对象统一管理和控制。从而将调用者和实现类解耦
详细分类:
1、简单工厂模式
2、工厂方法模式
3、抽象工厂模式
需满足的OOP七大原则:
1、开闭原则:对扩展开放,对修改关闭
2、依赖倒转原则:接口编程,非实现编程
3、迪米特原则:只与你直接的朋友通信,而避免与陌生人通信
一、简单工厂模式
1、代码实例
以生产车为实例,进行代码程度理解
1.1 初始new方式实例化对象
总结:
开发层面:接口—>实现—>调用者
1.1.1 接口类:Car类
1 | public interface Car { |
1.1.2 实现类
(1)实现类:五菱宏光
1
2
3
4
5
6
7 public class WuLing implements Car{
//重写接口类的方法
public void name() {
System.out.println("五菱宏光!");
}
}(2)实现类:特斯拉
1
2
3
4
5
6
7 public class Tesla implements Car{
//重写接口类的方法
public void name() {
System.out.println("特斯拉!");
}
}
1.1.3 调用者—Consumer
1 | public class Consumer { |
结果:
1
2 五菱宏光!
特斯拉!分析:
new方法的接口,需要了解所有的实现类
缺点:需要了解实现类的所有细节
1.2 factory方法实例化对象
在1.1的基础之上进行一定程度的修改
总结:
开发层面:接口—>实现—>工厂类—>调用者
(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 {
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)的基础之上进行进一步的研究
总结:
开发层面:接口—>实现—>工厂接口—>工厂实现—>调用者
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 {
public Car getCar() {
return new Wuling();
}
}(2)TeslaFactory类
1
2
3
4
5
6 public class TeslaFactory implements carFactory {
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、应用实例
以手机和路由器为实例
产品等级结构:小米手机和华为手机,都是手机的产品制造商,因此,可以称为同一个产品等级结构
产品簇:小米手机和小米路由器,都由小米公司来制造,因此属于同一个产品簇
总结:所有同一个产品簇中的产品都是由同一个工厂来生产的,但却属于不同的产品等级结构。
2、代码实例
2.1 产品接口类
2.1.1 手机产品接口类—IphoneProduct
1 | //手机产品接口 |
2.1.2 路由器产品接口类— IRouterProduct
1 | //路由器产品接口 |
2.2 产品接口类的实现
2.2.1 手机接口实现—小米手机—Xiaomi
1 | //小米手机 |
2.2.2 手机接口实现—华为手机—Huawei
1 | //华为手机 |
2.2.3 路由器接口实现—小米路由器—Xiaomi
1 | //小米路由器 |
2.2.4 路由器接口实现—华为路由器—Huawei
1 | //华为路由器 |
2.3 工厂的接口类—产品接口的接口—IProductFactory
1 | public interface IProductFactory { |
2.4 工厂接口类的实现
2.4.1 小米工厂类—XiaomiFactory
1 | public class XiaomiFactory implements IProductFactory { |
2.4.2 华为工厂类—HuaweiFactory
1 | public class HuaweiFactory implements IProductFactory { |
2.5 客户端调用—client类
1 | public class client { |
结果:
==============小米系列产品===============
小米打电话!
小米发短信!
打开小米wifi
==============华为系列产品===============
开启华为手机!
华为打电话!
华为设置
四、三者区别
简单工厂:用来生产同一等级结构中的任意产品(对于增加新的产品,无能为力)
工厂方法:用来生产同一登记结构中的固定产品(支持增加任意产品)
抽象工厂:用来生产不同产品簇的全部产品(对于增加新的产品,无能为力;支持增加产品簇)