携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第23天,点击查看活动详情
一、简介
工厂模式可以分为两种,简单工厂模式、抽象工厂模式。工厂模式也是平时开发中最常用的一种设计模式
二、简单工厂模式
基本介绍
- 简单工厂模式属于创建型模式,是工厂模式的一种
- 定义了一个创建对象的类,由某个类来封装实例化对象的行为
- 在软件开发中,当我们会用到大量的创建某种、某类或者某对象时,就会使用到工厂模式
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点: 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。\
类图
\
三、抽象工厂模式
基本介绍
1)抽象工厂模式:定义了一个接口用于创建相关或有依赖关系的对象蔟,而无需指明具体的类
2)抽象工厂模式可以将简单工厂模式和工厂方法进行整合
3)从设计层面来看,抽象工厂模式是对简单工厂模式的改进
4)将工厂抽象成两层,AbsFactory和具体实现的工厂子类,程序员可以根据创建对象类型使用对应的工厂子类,这样将单个的简单工厂变成了工厂簇
优点: 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点: 产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。
类图
\
四、工厂模式在jdk中的应用
Calendar类
Calendar cal = Calendar.getInstance();
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}
五、抽象工厂在实际开发中的举例
支付平台对接有时需要对接各种支付平台,那么抽象工厂就是一个很好的选择
简单看下类图
\
这里的逻辑就是一个支付抽象接口总类 AbstractPaymentGatewayService,后续根据支付总类型划分各个类型的抽象类 例如阿里支付、微信支付 对应的就是AbstractAliPaymentGatewayService、AbstractWeixinPaymentGatewayService
在向下划分即具体的支付接口
贴上代码
模块
PaymentGatewayService.class
package com.example.pay;
public interface PaymentGatewayService {
String getChannel();
void pay();
}
PaymentGatewayFactoryService.class
package com.example.pay;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class PaymentGatewayFactoryService {
private Map<String,PaymentGatewayService> services = new ConcurrentHashMap<>();
/***
* @Description: 将对象注册到map
* @param channelId 渠道
*/
protected void register(String channelId,PaymentGatewayService service){
String[] gateIdArray = channelId.split(",");
for (String gateId : gateIdArray) {
if (null != services.get(gateId)) {
System.out.println("error");
}
services.put(gateId, service);
}
}
/**
* @Description: 获取对象
* @param gateId 渠道id
*/
public PaymentGatewayService getPaymentGatewayService(String gateId) {
PaymentGatewayService paymentGatewayService = services.get(gateId);
if (null == services.get(gateId)) {
System.out.println("error");
}
return paymentGatewayService;
}
}
AbstractPaymentGatewayService.class
package com.example.pay;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class AbstractPaymentGatewayService implements InitializingBean,PaymentGatewayService {
@Autowired
private PaymentGatewayFactoryService factory;
@Override
public void afterPropertiesSet() throws Exception {
factory.register(this.getChannel(),this);
}
}
AbstractAliPaymentGatewayService.class\
package com.example.pay.alipay;
import com.example.pay.AbstractPaymentGatewayService;
public abstract class AbstractAliPaymentGatewayService extends AbstractPaymentGatewayService {
protected String host = "xxxx";
}
AliPaymentApp.class
package com.example.pay.alipay;
public class AliPaymentApp extends AbstractAliPaymentGatewayService{
@Override
public String getChannel() {
return "ali-app";
}
@Override
public void pay() {
System.out.println("App pay");
}
}
AliPaymentH5.class
package com.example.pay.alipay;
public class AliPaymentH5 extends AbstractAliPaymentGatewayService{
@Override
public String getChannel() {
return "ali-h5";
}
@Override
public void pay() {
System.out.println("h5 pay");
}
}
AbstractWeixinPaymentGatewayService.class
package com.example.pay.weixin;
import com.example.pay.AbstractPaymentGatewayService;
public abstract class AbstractWeixinPaymentGatewayService extends AbstractPaymentGatewayService {
}
WeixinJSAPIPay.class
package com.example.pay.weixin;
public class WeixinJSAPIPay extends AbstractWeixinPaymentGatewayService {
@Override
public String getChannel() {
return "JS-API";
}
@Override
public void pay() {
System.out.println("jsapi pay");
}
}
以上代码可以直接用于生产实践,具体功能需参考具体业务实现