设计模式
介绍
设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路,他不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳定性以及安全性的解决方案。
意义
- 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的的充分理解。
- 正确使用设计模式具有以下优点:
- 可以提高程序员的思维能力、编程能力和设计能力。
- 使面试程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
- 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强
工厂模式
介绍
工厂模式用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。实际上,如果创建对象的逻辑并不复杂,那我们直接通过new来创建对象就可以了,不需要使用工厂模式。
当创建逻辑比较复杂,是一个“大工程”的时候,我们就考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。
当每个对象的创建逻辑都比较简单的时候,我推荐使用简单工厂模式,将多个对象的创建逻辑放到一个工厂类中。
当每个对象的创建逻辑都比较复杂的时候,为了避免设计一个过于庞大的工厂类,我们推荐使用工厂方法模式,将创建逻辑拆分得更细,每个对象的创建逻辑独立到各自的工厂类中。
作用
-
封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。
-
代码复用:创建代码抽离到独立的工厂类之后可以复用。
-
隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象。
-
控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。
应用场景
依赖注入框架,比如Spring IOC、Google Guice,它用来集中创建、组装、管理对象,跟具体业务代码解耦,让程序员聚焦在业务代码的开发上。DI框架已经成为了我们平时开发的必备框架。
简单工厂模式
该模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象,其UML类图如下:
下面以一个支付场景来模拟该模式:
**支付接口:**规范支付标准
public interface PaymentService {
public void pay();
}
两个支付接口实现类:
1、阿里支付
public class AliPaySerciceImpl implements PaymentService {
@Override
public void pay() {
System.out.println("执行阿里支付接口的程序。。。");
}
}
2、微信支付
public class WeChatServiceImpl implements PaymentService {
@Override
public void pay() {
System.out.println("执行微信支付程序。。。");
}
}
支付接口工厂接口:
public interface PayEasyFactory {
//创建支付服务接口对象
public PaymentService createPaymentService();
}
两种支付方式接口实现类对象的生产工厂
1、阿里支付接口工厂
public class AliPayEasyFactory implements PayEasyFactory{
@Override
public PaymentService createPaymentService() {
return new AliPaySerciceImpl();
}
}
2、微信支付接口工厂
public class WeChatPayEasyFactory implements PayEasyFactory{
@Override
public PaymentService createPaymentService() {
return new WeChatServiceImpl();
}
}
静态工厂模式: 通过不同的参数得到不同的支付接口对象
public class PayMentFactory {
public static PaymentService getPaymentService(String payType) {
PaymentService paymentService = null;
switch (payType) {
case "ali_pay":
paymentService = new AliPaySerciceImpl();
break;
case "wechat_pay":
paymentService = new WeChatServiceImpl();
break;
}
return paymentService;
}
}
测试类:
public class TestEasyFactoryMode {
//需要什么支付对象,就用什么支付对象的工厂生成对应的支付对象
public static void main(String[] args) {
PayEasyFactory payEasyFactory = new AliPayEasyFactory();
PaymentService paymentService = payEasyFactory.createPaymentService();
paymentService.pay();
PaymentService paymentService1 = PayMentFactory.getPaymentService("wechat_pay");
paymentService1.pay();
}
}
工厂方法模式
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂,其UML类图如下:
也就是定义一个抽象工厂,其定义了产品的生产接口,但不负责具体的产品,将生产任务交给不同的派生类工厂。这样不用通过指定类型来创建对象了。
生产不同产品的抽象类:
public interface PayAbstractFactory {
PaymentService makePayment();
}
生产阿里支付的工厂:
public class AliPayFactory implements PayAbstractFactory{
@Override
public PaymentService makePayment() {
return new AliPaySerciceImpl();
}
}
生产微信支付的工厂:
public class WeChatPayFactory implements PayAbstractFactory{
@Override
public PaymentService makePayment() {
return new WeChatServiceImpl();
}
}
测试类:
public class TestFactoryMethodMode {
public static void main(String[] args) {
PayAbstractFactory ali = new AliPayFactory();
PaymentService paymentService1 = ali.makePayment();
paymentService1.pay();
PayAbstractFactory wei = new WeChatPayFactory();
PaymentService paymentService2 = wei.makePayment();
paymentService2.pay();
}
}
抽象工厂模式
上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品(AbstractProduct),如果要生成另一种产品,应该怎么表示呢?
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。
从上面类图结构中可以清楚的看到如何在工厂方法模式中通过增加新产品接口来实现产品的增加的。
下面通过冰淇淋的案例来解释该模式。
定义冰淇淋接口:
public interface BigIceCream {
public void taste();
}
public interface SmallIceCream {
public void taste();
}
定义冰淇淋的实现产品
public class BigAppleIceCream implements BigIceCream {
@Override
public void taste() {
System.out.println("这是苹果味冰激凌(大份)");
}
}
public class BigBananaIceCream implements BigIceCream {
@Override
public void taste() {
System.out.println("这是香蕉味冰激凌(大份)");
}
}
public class SmallAppleIceCream implements SmallIceCream {
@Override
public void taste() {
System.out.println("这是苹果味冰激凌(小份)");
}
}
public class SmallBananaIceCream implements SmallIceCream {
@Override
public void taste() {
System.out.println("这是香蕉味冰激凌(小份)");
}
}
下面定义生产冰淇淋的工厂接口:
public interface IceCreamFactory {
public BigIceCream createBigIceCream();
public SmallIceCream createSmallIceCream();
}
生产冰淇淋的工厂接口实现类
public class AppleIceCreamFactory implements IceCreamFactory {
@Override
public BigIceCream createBigIceCream() {
return new BigAppleIceCream();
}
@Override
public SmallIceCream createSmallIceCream() {
return new SmallAppleIceCream();
}
}
public class BananaIceCreamFactory implements IceCreamFactory {
@Override
public BigIceCream createBigIceCream() {
return new BigBananaIceCream();
}
@Override
public SmallIceCream createSmallIceCream() {
return new SmallBananaIceCream();
}
}
测试类:
public class TestAbstractFactoryMode {
public static void main(String[] args) {
//生产苹果味冰激凌
IceCreamFactory appleIceCreamFactory = new AppleIceCreamFactory();
BigIceCream appleBigIceCream = appleIceCreamFactory.createBigIceCream();
SmallIceCream appleSmallIceCream = appleIceCreamFactory.createSmallIceCream();
appleBigIceCream.taste();
appleSmallIceCream.taste();
//生产香蕉味冰激凌
IceCreamFactory bananaIceCreamFactory = new BananaIceCreamFactory();
BigIceCream bananaBigIceCream = bananaIceCreamFactory.createBigIceCream();
SmallIceCream bananaSmallIceCream = bananaIceCreamFactory.createSmallIceCream();
bananaBigIceCream.taste();
bananaSmallIceCream.taste();
}
}
总结
上面介绍的三种工厂模式有各自的应用场景,实际应用时能解决问题满足需求即可,可灵活变通,无所谓高级与低级。
此外无论哪种模式,由于可能封装了大量对象和工厂创建,新加产品需要修改已定义好的工厂相关的类,因此对于产品和工厂的扩展不太友好, 利弊需要权衡一下。