java开发中工厂方法模式和策略模式

java开发中工厂方法模式和策略模式

一、工厂方法模式(简单工厂、工厂方法、抽象工厂)

下文都以实现邮箱验证码和图片验证码为例。

0.在不使用任何设计模式的情况下:

/**
     * 没有任何设计模式的情况
     * @param dto
     * checkCodeType   pic:图片验证码 email:邮箱验证码
     * @return
     */
    public CheckCodeResultVo generateCheckCodeNoDesignPattern(CheckCodeParamsDto dto) {
        
        //忽略了参数校验

        if("pic".equals(dto.getCheckCodeType())){
            //需要完成很多任务,比如生成base64编码的图片、生成uuid等标识id来作为保存到redis的key、将生成的正确验证码保存到redis,登录时拿出来校验。
            return generatePicCheckCode(dto);
        }else if("email".equals(dto.getCheckCodeType())){
            //需要完成很多任务,比如组合邮件、发邮件,将邮箱号作为保存到redis的key、将生成的正确验证码保存到redis,登录时拿出来校验。
            return generateEmailCheckCode(dto);
        }else{
            //.......
            throw new RuntimeException("参数错误,没有匹配的type");
        }
    }

可以看到,存在以下问题:

  1. 如果未来需要增加其他的生成验证码的方式,需要继续写else if,继续在generateCheckCodeNoDesignPattern这个方法及类中补方法,会导致这个类变得非常臃肿。并且方法内存在大量的if else。

  2. 这种开发的结果就是违反了软件设计的开闭原则、导致代码耦合性太强,代码开发应该满足高内聚低耦合。

    开闭原则:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去 修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。

1.简单工厂

​ 简单工厂模式从类图上来看其实就是多了一个工厂类,在该工厂类中编写上面那一大坨代码,而我们的serviceimpl业务处理类只需要使用,不关心对type的判断。(该图来源于黑马程序员于老师,课程链接:黑马程序员课程链接
请添加图片描述

所以结果就是,简单工厂模式下,在我们的验证码service类中,我们只使用,也就是这样:

/**
 * 简单工厂模式的情况
 * @param dto
 * 
 * @return
 */
public CheckCodeResultVo generateCheckCodeSimpleFactoryPattern(CheckCodeParamsDto dto) {

    //忽略了参数校验

    //在spring开发中也可以直接把CheckCodeFactory类交给IOC容器管理,然后注入进来,不需要new
    CheckCodeFactory checkCodeFactory = new CheckCodeFactory();
    //这样就拿到了具体的实现类,我们就可以调用generateCheckCode来根据type生成验证码。
    //CheckCode是接口,PicCheckCodeImpl和EmailCheckCodeImpl是其实现类
    CheckCode checkCode = checkCodeFactory.getCheckCode(dto);
    //调用生成验证码的方法
    checkCode.generateCheckCode(dto);
    return vo;
}

​ 而对于工厂类:

public class CheckCodeFactory {
    public CheckCode getCheckCode(CheckCodeParamsDto dto) {

        if("pic".equals(dto.getCheckCodeType())){
            
            return new PicCheckCodeImpl(dto);
        }else if("email".equals(dto.getCheckCodeType())){
            
            return EmailCheckCodeImpl(dto);
        }else{
            //.......
            throw new RuntimeException("参数错误,没有匹配的type");
        }
    }

}

好处就是避免了直接修改业务类的代码,但是缺点是,增加新功能的时候仍然需要修改工厂类,还是违背了”开闭原则“。

注意:在这个代码块中,是先通过工厂模式拿到对应的对象,再去调用方法。这是工厂模式和策略模式的区别之一。

工厂方法模式

工厂方法模式从类图上来看其实就是在简单工厂的基础上多了若干个具体实现的工厂类,而原来在简单工厂中的工厂类,变成了抽象工厂接口或抽象类。(该图来源于黑马程序员于老师,课程链接:黑马程序员课程链接

请添加图片描述

所以,外界想要使用具体的功能的时候(比如想要使用生成邮箱验证码的功能),只需要去注入该工厂实现类,然后调用对应方法即可。这样的话,未来新增比如短信验证码的时候,只需要继续编写验证码工厂接口的实现类,然后在业务中使用方法即可,这样也避免了大量的if else(因为把n个if else变成了某个接口的n个实现类)。

注意:抽象工厂接口中,只有一个方法:

public interface CheckCodeFactory {
    CheckCode getCheckCode();
}

而对象的创建,则在具体的实现类中。

public class PicCheckCodeFactory {
    public CheckCode getCheckCode() {
            return new PicCheckCodeImpl();
        }
}

抽象工厂模式

​ 抽象工厂模式从类图上来看其实就是在工厂方法模式的基础上,将多组具有相近功能的业务的抽象工厂,再次抽象出一个更大的抽象工厂,将这些工厂都统一起来,如下:(该图来源于黑马程序员于老师,课程链接:黑马程序员课程链接)
请添加图片描述

*** 综上:其实用的最多的是工厂方法模式。***

策略模式

​ 策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。

​ 策略模式的主要角色如下:

  • 抽象策略类:这是一个接口或抽象类。此角色给出所有的具体策略类所需的接口。

    • 具体策略类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
      * 环境类:持有一个策略类的引用,最终给客户端/业务调用。

类图如下:(该图来源于黑马程序员于老师,课程链接:黑马程序员课程链接)

请添加图片描述

在学习工厂模式和策略模式的时候,我经常不明白工厂方法和策略模式有什么区别,明明都是一个抽象类或接口,多个实现逻辑的实现类。

下面先说明策略模式和工厂模式的区别

​ 相似点:

​ 在模式结构上,两者很相似(特别是工厂方法模式和策略模式);

​ 不同点:

  1. 两者在关注的点上的不同:工厂模式更加关心的是对象的创建,所以我上面的例子中是通过工厂模式,把if else中大量的对象创建拆分开来;

    而策略模式更偏向于行为的封装,对算法的封装,对问题解决方案的区分。

  2. 使用场景的不同:工厂模式是创建型的设计模式,通过接受指令,创建出符合要求的对象实例;它主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关;

    策略模式是为了解决的是策略的切换与扩展,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。

所以从上面可以看出来,为什么在工厂模式中,我都是在先创建对象,然后再在业务中调用对应的方法。

而现在,在策略模式中,其实就不关心对象的创建了,而是行为,也就是业务。所以其实区别就是,抽象策略接口的实现类策略中,完成的具体的业务功能,然后在上下文对象中,实现能够让客户端/业务端通过type来调用到对应的策略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值