成为架构师的必经之路-掌握软件设计模式(二)
从原生社会的过渡-常见的工厂设计模式你认识了多少
「工厂设计模式的介绍」
工厂模式它提供了一种创建对象的最佳方式,就是我们在创建对象的时候不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。比如说,需要去购买一辆车,你会想车辆是如何进行组装吗?这并不需要,只需要去购买你想要的车的类型就可以,车的类型有轿车、跑车、SUV,直接去4S店购买即可(这个4S店就是工厂)。在日常可以看到,工厂生产电脑,但它只是生产品牌A的电脑吗?并不是的,还有B、C、D品牌电脑。在业务的开发中,支付可以说是很常见了,里面有统一下单和支付接口,具体的支付实现可以有微信、支付宝、银联等等。
用户调用了工厂类的CatFactory类来生成了一个CatService,用户就不需要了解到CatService类的实现过程,用户需要某一个类的时候就只需要调用它的工厂类,然后会返回一个实例给用户。
工厂模式有三种不同的方式实现
1、简单工厂模式:通过传入相关的类型来返回相对应的类,这种方式比较单一,可扩展性相对较差
2、工厂方式模式:通过实现类实现相对应的方法来决定所对应的返回结果,这种方式的可扩展性比较强
3、抽象工厂模式:基于上述的两种模式的拓展,并且支持细化产品。
「应用场景」
那么工厂模式它的应用场景有哪些呢?
解耦:分离职责,把复杂的对象的创建和使用的过程分开
复用代码,降低项目的维护成本:如果对象创建复杂并且多出需要用到,如果每一个地方都进行编写的话,会有很多重复性的代码。如果业务逻辑变更,这时候就要四处进行修改了。使用工厂模式进行统一的创建,就修改工厂类即可,降低成本难。
「简单工厂模式」
这种模式对对象的创建管理方式很简单,因为就是简单的对不同类的对象进行了一层简单的封装,该模式通过向工厂传递类型所指定的创建对象。在《设计模式》这本书里,把简单工厂模式看成工厂方法模式的一种特例,两者是归为一类的。
「工厂方法模式」
工厂方法模式又称为工厂模式,是对简单工厂模式的进一步抽象化,好处就是可以让系统在不修改原来代码的情况下引进新的产品,就是满足了开闭原则。通过工厂的父类负责创建产品的公共接口,通过子类来确定所需要创建的类型。跟简单工厂来比的话,这种方法具有很多的可扩展性和复用性,同时也增强了代码的可读性。具体就是将类的实例化(具体产品的创建)延迟到工厂类里的子类(具体工厂)里去完成,子类来决定应该实例化哪一个类。
/**
* 工厂方法
*/
public interface PayFactory {
Pay getPay();
}
/**
* 具体产品工厂
*/
public class AliPayFactory implements PayFactory {
@Override
public Pay getPay() {
return new AliPay();
}
}
/**
* 抽象产品
*/
public interface Pay {
/**
* 统一下单
*/
void unifiedorder();
}
/**
* 具体产品
*/
public class AliPay implements Pay {
@Override
public void unifiedorder() {
System.out.println("支付宝支付 统一下单接口");
}
}
以上这种工厂方法模式符合了开闭原则,因为没增加一个产品类,只需要实现其他具体产品类的具体工厂类。也符合了单一职责的原则,每一个工厂只负责生产相对应的产品,使用者只需要知道产品的抽象类,不用关系其他的实现类,满足了迪米特法则、依赖倒置原则和里氏替换原则。
迪米特法则:最少知道原则,实体应当尽量少地与其他实体之间发生相互作用
依赖倒置原则:针对接口编程,依赖于抽象而不依赖于具体
里氏替换原则:俗称LSP, 任何基类可以出现的地方,子类一定可以出现, 对实现抽象化的具体步骤的规范
工厂方法模式的缺点
在添加新的产品时候,需要重新编写新的具体产品类,并且还要提供与之相对应的具体工厂类,我们知道,在系统中类的个数将成对增加时,也在一定的程度上对系统的复杂度产生了变更,这时候就有更多的类需要编译和运行了,会给系统带来一些额外的开销。所以考虑到系统的可扩展性,需要引入抽象层,在客户端代码里均使用抽象层来定义,这样增加了系统的抽象性与理解难度,并且的话在实现时还可能需要用到DOM、反射等等的一些技术,增加系统的实现难度。
「抽象工厂模式」
工厂方法模式引入了工厂的等级结构,解决了简单工厂模式里的工厂类职责过重的问题,但是工厂方法模式中的每一个工厂都只创建一类具体类的对象,后续发展会导致工厂类变得越来越多,所以将一些相关的具体类组合成一个具体类组,由同一个工厂来统一生产,抢到的是一些列相关的产品对象。
实现步骤
1、定义两个接口 Pay、Refund
2、创建具体的Pay产品、创建具体的Refund产品
3、创建抽象工厂 OrderFactory 接口里面两个方法 createPay/createRefund
4、创建支付宝产品族AliOderFactory,实现OrderFactory抽象工厂
5、创建微信支付产品族WechatOderFactory,实现OrderFactory抽象工厂
6、定义一个超级工厂创造器,通过传递参数获取对应的工厂
/**
* 超级工厂,定义同个产品族的其他相关子工厂
*/
public interface OrderFactory {
PayFactory createPay();
RefundFactory createRefund();
}
//产品族工厂的产品,可以不叫Factory,看公司团队规范,比如类名叫 IPay 也可以的
public interface PayFactory {
/**
* 统一下单
*/
void unifiedorder();
}
//产品族工厂
public class AliOrderFactory implements OrderFactory {
@Override
public PayFactory createPay() {
return new AliPay();
}
@Override
public RefundFactory createRefund() {
return new AliRefund();
}
}
//具体产品
public class AliPay implements PayFactory {
@Override
public void unifiedorder() {
System.out.println("支付宝支付 统一下单接口");
}
}
//超级工厂生产器,传参生产对应的子工厂
public class FactoryProducer {
public static OrderFactory getFactory(String type) {
if (type.equalsIgnoreCase("WECHAT")) {
return new WechatOrderFactory();
} else if (type.equalsIgnoreCase("ALI")) {
return new AliOrderFactory();
}
return null;
}
}
//Main函数使用
OrderFactory orderFactory = FactoryProducer.getFactory("ALI");
orderFactory.createPay().unifiedorder();
orderFactory.createRefund().refund();
到了这里你会想问工厂方法模式与抽象工厂方法模式有什么区别呢?当抽象工厂模式中每一个具体的工厂类只能创建一个产品对象,抽象工厂模式退化成工厂方法模式。
「抽象工厂的优点」:抽象工厂模式隔离了具体类的生成,这就使得客户无需知道什么被创建了。就是因为这种隔离,更换一个具体工厂的话就会变得相对来说比较容易了。在所有的具体工厂都实现抽象工厂中定义了哪些公共接口,所以只需要改变具体工厂的实例,就可以说在某一种程度上改变了整一个软件系统的行为。还有就是抽象工厂模式可以实现高内聚低耦合的这种设计目的,所以抽象工厂模式得到了广泛的应用。增加新的具体工厂和产品族也方便,无需更改现有的系统,符合了开闭原则。
「抽象工厂的缺点」:在添加新的产品对象的时候,很难以扩展抽象工厂这种方式来生产新种类的产品,这是因为在抽象工厂角色里规定了所有可能被创建到的产品,要支持新的种类产品也就说明了要就接口来进行扩展,而这样将会涉及到对抽象工厂里的角色和子类的修改,这样显然就会带来不便。开闭原则的倾斜性(增加了新的工厂和产品容易,但是增加新的产品等级结构麻烦)
「那什么是开闭原则的倾斜性?」
我们知道开闭原则是要求系统对扩展具有开放性,对修改有封闭性。通过扩展可以达到对功能增强的目的。对于增强功能这一块会涉及到多个产品族与产品的等级结构,所以功能的增强包括了两个方面:
1、增加系统的产品族,对于添加新的产品族,工厂方法就很好的支持了开闭原则,对于新添加的产品族,就只需要相对应的添加一个具体工厂就可以了,不用对现有的代码做修改。
2、增加新的产品的等级结构,对于增加产品的等级结构,这就需要对所有的工厂角色进行修改,包括了抽象的工厂类,在所有的工厂类里面都需要添加生成新的产品方法,这就不是很符合了开闭原则
抽象工厂为新产品族提供了方便,但不可以为新产品的等级结构添加提供这样的方便
- 点赞
- 收藏
- 关注作者
评论(0)