设计模式(一)单例工厂模式进行加载类

465 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

前言

如果你工作几年还经常通过New来实例化一个类,那么这篇可以来看看了,我们在写代码有一个很重要的原则就是解耦,通过解耦的方式让我们项目的代码更近简洁、清晰,不必一个地方改动很多地方都要进行修改,这篇来讲讲把类的实例化交给工厂来做,让我们代码的可扩展性较高。

工厂模式

何为工厂,顾名思义依靠某种介质生产我们所需要的东西,举个🌰正如有时候我们出去买东西,去普通商店买的东西就较贵,而去工厂店里面去买,则价格会相对优惠些,并且可买东西的种类也比较多,回过头我们看我们代码的设计模式。

Spring的工厂模式

关于工厂模式在Spring中体现比较常见的就是BeanFactory和FactoryBean,是Spring管理Bean的基础,这里有个对比的知识点,就是BeanFactory和FactoryBean的区别,了解Spring bean加载机制都知道,BeanFactory是IOC的核心,也是Spring的顶级接口;FactoryBean工厂是通过getObject方法来创建并返回对象,是一个针对Bean实现的定制化工厂,当然两者都离不开”工厂“两字。

传统模式

再结合我们的业务实现,举个业务场景,我们的订单系统在日常生成订单,然后通过结算系统进行付款结算的时候,通常对接的付款渠道不止一个,可能有多个,比如支付宝、微信支付、银行卡支付,这个时候我们去对这些渠道进行操作的时候,传统方式我们需要实现比如说3个接口,关于支付宝、微信、银行卡的接口,并且实现它们对应的业务方法,调取对应的第三方付款接口,最终将结果会写到数据库对应的表中。

2A9ED9C3-FEA5-411F-85E1-8A740C9C4743.png

单例、工厂模式设计

FE344511-2971-41C6-AFE5-05F9D07F6EE7.png

ChannelFactoryUtil

首先是创建工厂调用工具类,通过getFactory方法获取不同的渠道工厂。

方式一:

public class ChannelFactoryUtil {

    /**
     * 获取渠道工厂
     *
     * @param channelType
     * @return
     */
    public ChannelFactory getFactory(ChannelType channelType) {
        ChannelFactory channelFactory = null;

        switch (channelType) {
            case WX_CHANNEL:
                channelFactory = WxChannelFactory.getInstance();
                break;
            case PAYMENT_CHANNEL:
                channelFactory = PaymentChannelFactory.getInstance();
                break;
            case BANK_CHANNEL:
                channelFactory = BankChannelFactory.getInstance();
                break;
            default:
                // 未配置,直接走默认的服务
                channelFactory = CommonChannelFactory.getInstance();
                break;
        }

        return channelFactory;
    }
}

方式二:

如果这些渠道都需要进行发短息服务的对接,那么就可以通过,工厂的模式根据不同的channelType,获取到不同业务渠道对于发送短信的接口实现类。

public SendNoteService getService(ChannelType channelType) {
    SendNoteService sendNoteService = null;

    switch (channelType) {
        case WX_CHANNEL:
            sendNoteService = SpringContextUtils.getBean(WechatServiceImpl.class);
            break;
        case PAYMENT_CHANNEL:
            // ...
            break;
        case BANK_CHANNEL:
            // ...
            break;
        default:
            break;
    }

    return sendNoteService;
}

SendNoteService 公共发短信方法

public interface SendNoteService{

    void sendNoteMessage();
}

WechatServiceImpl

@Service
public class WechatServiceImpl implements WechatService,SendNoteService {

    /**
     * 微信支付方法
     */
    @Override
    public void wechatPayMethod() {
      
    }

    /**
     * 发短信
     */
    @Override
    public void sendNoteMessage() {
     //自定义实现微信的发短信方法
      ....
    }
}

ChannelFactory

这里声明ChannelFactory接口,用来初始化不同的service,实现不同的业务接口,可以针对每个渠道的不同写不同的sevice,返回统一都是接口类型;包括实现公共接口,这里我在ChannelFactory接口里,写了一个公共的service么,以及不同业务所需要的服务接口。

public interface ChannelFactory {

    //公共service
    CommonService factoryUserMethod();

    //可以去写不同针对不同业务的service

    //微信服务service
    WechatService getWechatServiceMethod();

    //支付宝服务service
    PaymentService getWechatServiceMethod();
    
    //银行服务service
    BankService getBankServiceMehtod();

}

WxChannelFactory

接下来就是实现不同业务渠道的工厂类,这里我只写一个,拿微信的业务渠道为例,实现ChannelFactory接口,获取对应的公共接口,并且通过单例模式进行初始化,这里使用的是懒汉模式+ duble check的加锁方式来实现的单例模式。

public class WxChannelFactory implements ChannelFactory {

    private volatile static ChannelFactory channelFactory = null;

    public WxChannelFactory() {
    }

    public static ChannelFactory getInstance() {

        if (channelFactory == null) {
            synchronized (WxChannelFactory.class) {
                if (channelFactory == null) {
                    channelFactory = new WxChannelFactory();
                }
            }
        }
        return channelFactory;
    }

    @Override
    public CommonService factoryUserMethod() {
        return SpringContextUtils.getBean(UserServiceImpl.class);
    }

    @Override
    public WechatService getWechatServiceMethod() {
        return null;
    }
}

执行Controller

@RestController
@Slf4j
public class TestController {

    @Autowired
    private ChannelFactoryUtil channelFactoryUtil;


    @GetMapping("/testMethod")
    public void testMethod(){
        //获取微信渠道的service
        ChannelFactory channelFactory = channelFactoryUtil.getFactory(ChannelType.WX_CHANNEL);
        WechatService wechatService =channelFactory.getWechatServiceMethod();
        //执行微信支付方法
        wechatService.wechatPayMethod();

        //获取微信发短信的方法
        SendNoteService wechatNoteService =channelFactoryUtil.getService(ChannelType.WX_CHANNEL);
        //执行发短信的方法
        wechatNoteService.sendNoteMessage();
    }
}

总结

通过上面工厂模式对我们的业务类进行加载,是不是更加清晰了呢,可扩展性强,耦合度较低,如果业务方法发生改变,只需要修改对应的底层业务方法,不需要对每个实现进行修改,通过设计模式让我们的代码结构清晰,同时能锻炼我们对项目构建的能力,何乐而不为呢。