首页 > 其他分享 >策略模式与模版模式的区别与应用

策略模式与模版模式的区别与应用

时间:2023-03-23 10:07:20浏览次数:43  
标签:区别 模版 void 模式 strategy PayStrategy public

本文为博主原创,未经允许不得转载:

  最近在做项目的优化,由于项目在早期缺乏规划,在开发过程中,对于某一个业务的不同类型判断,增加了很多 if else ,代码的健壮性变得很差。

所以考虑使用设计模式中的策略模式与模版模式进行开发中的代码设计。且由于在使用过程中策略模式与模版模式经常一起使用,所以对这两种设计模式

进行一起整理记录下。

 

  1.模版模式:

    模版模式的定义:模板方法模式定义了一个算法的步骤,并允许子类别为一个或多个步骤提供其实践方式。让子类别在不改变算法架构的情况下,重新定义算法中的某些步骤。

    模版模式属于行为型设计模式,其意图是在一个方法里实现一个算法,并定义延迟算法的某些步骤,从而让其他类重新定义他们。

    项目中经常使用的RestTemplate,JdbcTemplate,RedisTemplate等都采用了模版模式的设计模式,因为在操作资源的时候,经常会涉及到打开资源链接

  关闭资源连接等,且为公用的模式,所以采用模版模式,然后将其定义为一个算法骨架,通过子类或实现类来实现算法的具体实现。

    example:

    定义一个模版:

public abstract class AbstractDataSourceTemplate {
    /**
     * 开启连接
     */
    abstract void open();

    /**
     * 执行操作
     */
    abstract void execute();

    /**
     * 关闭连接
     */
    abstract void close();

    /**
     * 模版方法
     */
    public final void run() {
        open();
        execute();
        close();
    }
}

    通过上述模版实现JdbcTemplate  与 RedisTemplate 

public class RedisDataSourceTemplate extends AbstractDataSourceTemplate {
    /**
     * 开启连接
     */
    @Override
    void open() {
        System.out.println("开启redis连接...");
    }

    /**
     * 执行操作
     */
    @Override
    void execute() {
        System.out.println("操作redis...");
    }

    /**
     * 关闭连接
     */
    @Override
    void close() {
        System.out.println("关闭redis连接...");
    }
}

JdbcTemplate  ::

public class JdbcDataSourceTemplate extends AbstractDataSourceTemplate {
    /**
     * 开启连接
     */
    @Override
    void open() {
        System.out.println("开启jdbc连接...");
    }

    /**
     * 执行操作
     */
    @Override
    void execute() {
        System.out.println("操作jdbc...");
    }

    /**
     * 关闭连接
     */
    @Override
    void close() {
        System.out.println("关闭jdbc连接...");
    }
}

使用

//jdbc模版
        AbstractDataSourceTemplate template = new JdbcDataSourceTemplate();
        template.run();
        System.out.println("----------------");
        //redis模版
        AbstractDataSourceTemplate template1 = new RedisDataSourceTemplate();
        template1.run();

总结

  • 封装不可变部分,扩展可变部分
  • 提取公共代码,便于维护
  • 行为由父类控制骨架/算法,子类实现
  • 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象
  • 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度

 2.策略模式:

    策略模式的应用比模版模式的应用场景更为常见。我们在开发过程中,经常会使用 if .. else if ( )  或 switch 。。 case。。等进行同一个业务的不同场景或类型判断。

  比如进行权限校验判断时,判断当前管理员是 超级管理员:userType ==1,如果是二级管理员  userType == 2....等等。这些场景都可以使用策略模式进行开发优化,可以避免

  很长的 if else 判断。

    策略模式的定义: 

策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。
  策略模式使得算法可以在不影响到客户端的情况下发生变化。
  其主要目的是通过定义相似的算法,替换if else 语句写法,并且可以随时相互替换。

    在其他博客中找到一个很好的场景,是支付场景,通过策略模式区分支付宝,银行卡,点券支付的场景。

    

package strategy;

public interface PayStrategy {
    String selectPayWay(Integer paycode);
}

 

  规定具体策略行为

package strategy;

public class PayContext {

    private PayStrategy payStrategy;

    public String selectPayWay(Integer payCode){
        payStrategy =  StrategyFactory.getInstance().create(payCode);
        return payStrategy.selectPayWay(payCode);
    }

    public PayStrategy getPayStrategy() {

        return payStrategy;
    }

    public void setPayStrategy(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }
}

 

支付宝付款实现类

package strategy.paystrategy;

import strategy.PayStrategy;

public class ALPayStrategy implements PayStrategy {

    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "支付宝支付成功";
    }
}

 

银行卡支付实现类

package strategy.paystrategy;

import strategy.PayStrategy;

public class CardPayStrategy implements PayStrategy {
    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "银行卡支付成功";
    }
}

 

微信支付实现类

package strategy.paystrategy;

import strategy.PayStrategy;

public class WeChatPayStrategy implements PayStrategy {

    @Override
    public String selectPayWay(Integer paycode) {
        //do something
        return "微信支付成功";
    }

}

 

创建策略类的工厂

package strategy;

import pay.PayWayEnum;
import strategy.paystrategy.ALPayStrategy;
import strategy.paystrategy.CardPayStrategy;
import strategy.paystrategy.PointCouponPayStrategy;
import strategy.paystrategy.WeChatPayStrategy;

import java.util.HashMap;
import java.util.Map;

public class StrategyFactory {

    private static StrategyFactory factory = new StrategyFactory();

    private StrategyFactory(){}

    private static Map strategyMap = new HashMap<>(16);

    static {
        strategyMap.put(PayWayEnum.AL_PAY.getCode(),new ALPayStrategy());
        strategyMap.put(PayWayEnum.WEICHAT_PAY.getCode(),new WeChatPayStrategy());
        strategyMap.put(PayWayEnum.CARD_PAY.getCode(),new CardPayStrategy());
        strategyMap.put(PayWayEnum.PONIT_COUPON_PAY.getCode(),new PointCouponPayStrategy());
    }

    public PayStrategy create(Integer payCode){
        return (PayStrategy) strategyMap.get(payCode);
    }

    public static StrategyFactory getInstance(){
        return factory;
    }

}

 

实现客户端

package strategy;

public class Client {

    public static void main(String[] args) {
        PayContext payContext = new PayContext();
        System.out.println(payContext.selectPayWay(100));
    }
}

 

最后在贴一个枚举类

package pay;

public enum PayWayEnum {

    /**微信支付*/
    WEICHAT_PAY("微信支付",100),
    /**支付宝支付*/
    AL_PAY("支付宝支付",101),
    /**银行卡支付*/
    CARD_PAY("银行卡支付",102),
    /**点券支付*/
    PONIT_COUPON_PAY("点券支付",103);

    private String msg;
    private Integer code;

    PayWayEnum(String msg, Integer code) {
        this.msg = msg;
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public Integer getCode() {
        return code;
    }
}

  从上面代码中,我们可以看到,我们完全消除了对状态码进行判断的那些if…else的冗余代码,取而代之是直接由客户端决定使用哪种算法,

然后交由上下文获取结果。极大的增强的了扩展性,隐藏了内部实现的细节,当然我们也可以看到,策略模式由于独立策略的实现,

也使得系统内部增加了很多策略,对客户端来必须知道这些策略类实现的是那些策略,而且需要知道具体的策略条件。

  然而在实际的生产环境中我们可能不会像示例代码这样干,在实际的生产环境中我们一般会结合spring来对我们所需的策略进行操作,

这边我可以给大家有个具体的思路,大家可以通过这个思路来想想,自己在实际生产环境会怎样操作

1.首先和上面代码一样定义一个Strategy接口,其中有一个operation的函数交给具体业务去实现
2.根据自己的业务,会拥有很多的策略类实现该接口;将这些类注册到spring Bean容器中提供使用。
3。通过客户端传值,从spring容器中获取Strategy实例
4.最终来执行operation函数

 


 



标签:区别,模版,void,模式,strategy,PayStrategy,public
From: https://blog.51cto.com/u_15535797/6144359

相关文章

  • jsp 静态引入<%@ include %> 动态引入<jsp:include> 区别
    1.首先先介绍下,jsp机制: servlet容器,先将jsp转化成servlet,然后编译成.class文件,放置容器缓冲区【tomcat的work目录下】。每次调用jsp时,服务器会读取编译好的servler.class,......
  • 20.(行为型模式)java设计模式之迭代器模式
    一、什么是迭代器模式(IteratorPattern)   提供—种方法顺序访问一个聚合对象中各个元素,而又无须暴露该对象的内部实现,属于行为型模式。应用场景:   —般来说,迭......
  • Unity中,区别LookAt与LookRotation 一直不太理解的问题.....
    详细的资料可以看这个大佬总结的:参考资料我这里直接用图结合着说:首先呢,我们的主角要看向敌人,下图是还没看向之前:  使用LookAt函数看向敌人后,Z轴看向敌人(也是正面看......
  • QPushButton::clicked和QPushButton::click有什么区别
    QPushButton::clicked是一个信号,当按钮被用户点击时发出。它可以携带一个布尔值参数,表示是否按钮被按下QPushButton::click是一个槽,当调用它时,会模拟按钮被点击的效果,并......
  • nginx的location与proxy_pass指令超详细讲解及其有无斜杠( / )结尾的区别
    本文所使用的环境信息如下:windows11(主机系统)virtual-box-7.0环境下的ubuntu-18.04nginx-1.22.1(linux)斜杠结尾之争实践中,nginx里最常用的指令就是location和pr......
  • nginx的location与proxy_pass配置超详细讲解及其有无斜杠( / )结尾的区别
    本文所使用的环境信息如下:windows11(主机系统)virtual-box-7.0环境下的ubuntu-18.04nginx-1.22.1(linux)斜杠结尾之争实践中,nginx里最常用的指令就是location和pr......
  • jsp和html的区别
    JSP代表JavaServerPages;它主要用于开发动态网页,文件的扩展名为.jsp。JSP技术允许快速开发并易于维护所述信息丰富的动态网页。JSP网页基于HTML,XML或其他文档类型。他们还......
  • 浅析Facebook的盈利模式(转)
    作为全球最大的社交网站,Facebook仍在以惊人的步伐向前迈进。在很多人看来,这样的一个网站要赚钱一定很容易,估计光靠卖卖广告就能赚很多吧。是的,没错,广告肯定是Facebook的一......
  • 框架、模式、架构、构件、组件、中间件概要
    简单来说:框架(Framework)解决某一方面应用问题的半成品软件模式(Pattern)为解决某一类问题而提出的一种解决方案,是方法论。架构(Architecture)整体解决方案......
  • 设计模式之迭代器模式
    个人理解:通过迭代器模式无需知道底层结构,实现数据遍历场景:有书存放在书架上,怎么去取书?代码如下:作用:将书放到书架中,并将书的名字按顺序显示出来示意图:  集合接口总......