ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

架构师内功心法-----策略模式与责任链模式

2021-04-13 15:04:11  阅读:92  来源: 互联网

标签:return String 模式 class ----- private new 架构师 public


策略模式与责任链模式


策略模式

策略模式又叫政策模式,它是将定义的算法家族分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户,属于行为型模式。
当存在大量if…else时,策略模式可以发挥作用,策略模式可以消除大量的if…else。

应用场景

1.针对同一类型问题,有多种处理方式,每一种都能独立解决问题。
2.算法需要自由切换的场景。

实际场景:移动支付、个人所得税(不同的薪资交不同的税)

通用类图

策略模式一般包含三种角色:

  • 上下文角色(Context):用户操作入口,该角色持有抽象策略角色,解耦策略与客户端,使得当策略发生改变时不影响客户端的使用。

  • 抽象策略角色(Strategy):规定策略或算法的行为

  • 具体策略角色(ConcreteStrategy):具体的策略算法

案例演示

优惠促销

存在以下场景,用户进行购买商品时,商家可能会搞活动,而每个活动都有不同的优惠,比如:优惠券抵扣、返现促销、拼团优惠等等,使用策略模式设计该场景。

抽象策略角色

public interface IPromotionStrategy {
    void doPromotion();
}

具体策略角色 返现促销

public class CashbackStrategy implements IPromotionStrategy {
    public void doPromotion() {
        System.out.println("返现,直接打款到支付宝账号");
    }
}

具体策略角色 优惠券抵扣

public class CouponStrategy implements IPromotionStrategy {
    public void doPromotion() {
        System.out.println("使用优惠券抵扣");
    }
}

具体策略角色 拼团优惠

public class GroupbuyStrategy implements IPromotionStrategy {
    public void doPromotion() {
        System.out.println("5人成团,可以优惠");
    }
}

具体策略角色 无优惠

public class EmptyStrategy implements IPromotionStrategy {
    public void doPromotion() {
        System.out.println("无优惠");
    }
}

标准上下文

public class PromotionContext {
    private IPromotionStrategy iPromotionStrategy;

    public PromotionContext(IPromotionStrategy iPromotionStrategy) {
        this.iPromotionStrategy = iPromotionStrategy;
    }

    public void doPromotion(){
        iPromotionStrategy.doPromotion();
    }
}


由于策略模式的策略是由用户指定,因此需要先判断是什么策略,明显可知switch中是简单工厂模式,因此使用工厂替代上下文。

工厂替代上下文

工厂类

public class PromotionStrategyFacory {

    private static Map<String,IPromotionStrategy> PROMOTIONS = new HashMap<String,IPromotionStrategy>();

    static {
        PROMOTIONS.put(PromotionKey.COUPON,new CouponStrategy());
        PROMOTIONS.put(PromotionKey.CASHBACK,new CashbackStrategy());
        PROMOTIONS.put(PromotionKey.GROUPBUY,new GroupbuyStrategy());
    }

    private static final IPromotionStrategy EMPTY = new EmptyStrategy();

    private PromotionStrategyFacory(){}

    public static IPromotionStrategy getPromotionStrategy(String promotionKey){
        IPromotionStrategy strategy = PROMOTIONS.get(promotionKey);
        return strategy == null ? EMPTY : strategy;
    }
    private interface PromotionKey{
        String COUPON = "COUPON";
        String CASHBACK = "CASHBACK";
        String GROUPBUY = "GROUPBUY";
    }

    public static  Set<String> getPromotionKeys(){
        return PROMOTIONS.keySet();
    }
}

在线支付

付款时,有多种选择,微信支付、支付宝支付、银联支付、京东支付等等,可使用策略模式设计。

抽象策略类

public abstract class Payment {

    public abstract String getName();

    //通用逻辑放到抽象类里面实现
    public MsgResult pay(String uid, double amount){
        //余额是否足够
        if(queryBalance(uid) < amount){
            return new MsgResult(500,"支付失败","余额不足");
        }
        return new MsgResult(200,"支付成功","支付金额" + amount);
    }

    protected abstract double queryBalance(String uid);
}

具体策略类 支付宝支付

public class AliPay extends Payment {
    public String getName() {
        return "支付宝";
    }

    protected double queryBalance(String uid) {
        return 900;
    }
}

具体策略类 京东支付

public class JDPay extends Payment {
    public String getName() {
        return "京东白条";
    }

    protected double queryBalance(String uid) {
        return 500;
    }
}

具体策略类 银联支付

public class UnionPay extends Payment {
    public String getName() {
        return "银联支付";
    }

    protected double queryBalance(String uid) {
        return 120;
    }
}

具体策略类 微信支付

public class WechatPay extends Payment {
    public String getName() {
        return "微信支付";
    }

    protected double queryBalance(String uid) {
        return 263;
    }
}

策略工厂

public class PayStrategyFactory {
    public static  final String ALI_PAY = "AliPay";
    public static  final String JD_PAY = "JdPay";
    public static  final String WECHAT_PAY = "WechatPay";
    public static  final String UNION_PAY = "UnionPay";
    public static  final String DEFAULT_PAY = ALI_PAY;

    private static Map<String,Payment> strategy = new HashMap<String,Payment>();

    static {
        strategy.put(ALI_PAY,new AliPay());
        strategy.put(JD_PAY,new JDPay());
        strategy.put(WECHAT_PAY,new WechatPay());
        strategy.put(UNION_PAY,new UnionPay());
    }

    public static Payment get(String payKey){
        if(!strategy.containsKey(payKey)){
            return strategy.get(DEFAULT_PAY);
        }
        return strategy.get(payKey);
    }
}

支付结果

public class MsgResult {
    private int code;
    private Object data;
    private String msg;

    public MsgResult(int code, String msg, Object data) {
        this.code = code;
        this.data = data;
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "MsgResult{" +
                "code=" + code +
                ", data=" + data +
                ", msg='" + msg + '\'' +
                '}';
    }
}

订单

public class Order {
    private String uid;
    private String orderId;
    private double amount;

    public Order(String uid, String orderId, double amount) {
        this.uid = uid;
        this.orderId = orderId;
        this.amount = amount;
    }

    public MsgResult pay(){
        return pay(PayStrategyFactory.DEFAULT_PAY);
    }

    public MsgResult pay(String payKey){
        Payment payment = PayStrategyFactory.get(payKey);
        System.out.println("欢迎使用" + payment.getName());
        System.out.println("本次交易金额为" + amount + ",开始扣款");
        return payment.pay(uid,amount);
    }
}

源码应用

spring下的Resource:根据不同的资源有不同的读取方法
spring实例化bean的类InstantiationStrategy:原生bean和代理bean

作业

1.改进优惠促销案例,通过配置文件存放策略关键字

properties文件读取工具类

public class PropertiesReader {
    /**
     * 读取properties
     *
     **/
    public static Map<String,String> read(String propertiesLocation){
        Map<String,String> map = new HashMap<>(4);
        Properties properties = new Properties();
        ClassPathResource classPathResource = new ClassPathResource(propertiesLocation);

        try {
            properties.load(classPathResource.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        for (String stringPropertyName : properties.stringPropertyNames()) {
            map.put(stringPropertyName, (String) properties.get(stringPropertyName));
        }

        return map;
    }
}

strategy.properties

#策略模式
CASHBACK=com.yjf.secondpart.design.pattern.strategy.homework.CashbackStrategy
GROUPBY=com.yjf.secondpart.design.pattern.strategy.homework.GroupbuyStrategy
COUPON=com.yjf.secondpart.design.pattern.strategy.homework.CouponStrategy

策略工厂类

public class PromotionStrategyFactory {
    private PromotionStrategyFactory(){}

    private static Map<String,IPromotionStrategy> map = new HashMap<>();
    private static final String PROPERTYLOCATION = "strategy.properties";
    private static EmptyStrategy emptyStrategy = new EmptyStrategy();

    static {
        Map<String, String> read = PropertiesReader.read(PROPERTYLOCATION);
        for (Map.Entry<String, String> stringStringEntry : read.entrySet()) {
            Object o = null;
            try {
                o = Class.forName(stringStringEntry.getValue()).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            if(!(o instanceof IPromotionStrategy)){ continue; }
            map.put(stringStringEntry.getKey(), (IPromotionStrategy) o);
        }
    }

    public static IPromotionStrategy getPromotionStrategy(String promotionKey){
        if(!map.containsKey(promotionKey)){
            return emptyStrategy;
        }else{
            return map.get(promotionKey);
        }
    }

    public static Set<String> getPromotionKeys(){
        return map.keySet();
    }
}

2.每个优惠促销方案都是独立有效的,这正是策略模式的意义所在,但是优惠又往往是同时出现的,结合装饰器模式完成多重优惠设计。

抽象策略类

public abstract class AbstractPromotionStrategy {
    protected int amount;

    public AbstractPromotionStrategy(int amount){
        this.amount = amount;
    }

    int doPromotion(){
        return amount;
    }
}

具体策略类 无优惠

public class EmptyStrategy extends AbstractPromotionStrategy {
    public EmptyStrategy(int amount) {
        super(amount);
    }

    @Override
    public int doPromotion() {
        return super.doPromotion();
    }
}

抽象装饰器

public abstract class AbstractPromotionDecorator extends AbstractPromotionStrategy{
    protected AbstractPromotionStrategy abstractPromotionStrategy;

    public AbstractPromotionDecorator(AbstractPromotionStrategy abstractPromotionStrategy) {
        super(abstractPromotionStrategy.amount);
        this.abstractPromotionStrategy = abstractPromotionStrategy;
    }

    @Override
    int doPromotion() {
        return abstractPromotionStrategy.doPromotion();
    }
}

具体装饰器 组团优惠

public class GroupbuyStrategy extends AbstractPromotionDecorator {
    public GroupbuyStrategy(AbstractPromotionStrategy abstractPromotionStrategy) {
        super(abstractPromotionStrategy);
    }

    @Override
    int doPromotion() {
        return (int) (super.doPromotion() * 0.8f);
    }
}

具体装饰器 优惠劵

public class CouponStrategy extends AbstractPromotionDecorator {
    public CouponStrategy(AbstractPromotionStrategy abstractPromotionStrategy) {
        super(abstractPromotionStrategy);
    }

    @Override
    public int doPromotion() {
        float v = new Random().nextFloat();
        System.out.println(String.format("打%f折", v));
        return (int)(super.doPromotion() *  v);
    }
}


责任链模式

责任链模式是将链中每一个节点看做是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一个节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止,属于行为型模式。
责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理。

应用场景

1.多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定

实际场景:发起一个工作流程

通用类图

责任链模式一般包含两种角色:

  • 抽象处理者(Handler):定义一个处理请求的方法,并维护下一个处理节点的引用。
  • 具体处理者(ConcreteHandler):对请求进行处理,如果不是该节点的职责,则进行转发。

案例演示

登录案例

一段登录逻辑,包括用户名密码判空,进行登录,权限检查,原代码如下。

用户

public class Member {
    private String loginName;
    private String loginPass;
    private String roleName;

    public Member(String loginName, String loginPass) {
        this.loginName = loginName;
        this.loginPass = loginPass;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getLoginPass() {
        return loginPass;
    }

    public void setLoginPass(String loginPass) {
        this.loginPass = loginPass;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    @Override
    public String toString() {
        return "Member{" +
                "loginName='" + loginName + '\'' +
                ", loginPass='" + loginPass + '\'' +
                ", roleName='" + roleName + '\'' +
                '}';
    }
}

登录业务

public class MemberService {

    public void login(String loginName,String loginPass){
        if(StringUtils.isEmpty(loginName) ||
                StringUtils.isEmpty(loginPass)){
            System.out.println("用户名和密码为空");
            return;
        }
        System.out.println("用户名和密码不为空,可以往下执行");

        Member member = checkExists(loginName,loginPass);
        if(null == member){
            System.out.println("用户不存在");
            return;
        }
        System.out.println("登录成功!");

        if(!"管理员".equals(member.getRoleName())){
            System.out.println("您不是管理员,没有操作权限");
            return;
        }
        System.out.println("允许操作");

    }

    private Member checkExists(String loginName,String loginPass){
        Member member = new Member(loginName,loginPass);
        member.setRoleName("管理员");
        return member;
    }

    public static void main(String[] args) {
        MemberService service = new MemberService();
        service.login("tom","666");
    }

}

使用责任链模式,将逻辑切分成三段,三个职责节点进行处理。

抽象处理者

public abstract class Handler {
    protected Handler next;
    public void next(Handler next){ this.next = next;}

    public abstract void doHandler(Member member);
}

具体处理者 非空校验

public class ValidateHandler extends Handler {
    public void doHandler(Member member) {
        if(StringUtils.isEmpty(member.getLoginName()) ||
                StringUtils.isEmpty(member.getLoginPass())){
            System.out.println("用户名和密码为空");
            return;
        }
        System.out.println("用户名和密码不为空,可以往下执行");
        next.doHandler(member);
    }
}

具体处理者 登录校验

public class LoginHandler extends Handler {
    public void doHandler(Member member) {
        System.out.println("登录成功!");
        member.setRoleName("管理员");
        next.doHandler(member);
    }
}

具体处理者 权限校验

public class AuthHandler extends Handler {
    public void doHandler(Member member) {
        if(!"管理员".equals(member.getRoleName())){
            System.out.println("您不是管理员,没有操作权限");
            return;
        }
        System.out.println("允许操作");
    }
}

登录业务

public class MemberService {
    public void login(String loginName,String loginPass){
        Handler validateHandler = new ValidateHandler();
        Handler loginHandler = new LoginHandler();
        Handler authHandler = new AuthHandler();

        validateHandler.next(loginHandler);
        loginHandler.next(authHandler);
        validateHandler.doHandler(new Member(loginName,loginPass));
    }
}

当链中节点足够多时,当前链的结构就很复杂了,因此可以通过建造者模式构建复杂对象。

抽象处理者

public abstract class Handler<T> {
    protected Handler next;
    private void next(Handler next){ this.next = next;}

    public abstract void doHandler(Member member);

    public static class Builder<T>{
        private Handler<T> head;
        private Handler<T> tail;

        public Builder<T> addHandler(Handler handler){
                if (this.head == null) {
                    this.head = this.tail = handler;
                    return this;
                }
                this.tail.next(handler);
                this.tail = handler;
            return this;
        }

        public Handler<T> build(){
            return this.head;
        }
    }
}

登录业务

public class MemberService {

    public void login(String loginName,String loginPass){

        Handler.Builder builder = new Handler.Builder();

        builder.addHandler(new ValidateHandler())
                .addHandler(new LoginHandler())
                .addHandler(new AuthHandler());

        builder.build().doHandler(new Member(loginName,loginPass));
    }

}

源码应用

tomcat中的过滤器Filter
Netty中的ChannelHandler

标签:return,String,模式,class,-----,private,new,架构师,public
来源: https://blog.csdn.net/hx1176406648/article/details/115540335

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有