Java教程

Delegate 委派模式和代理模式strategy的区别?策略模式如何实现消除多层if else?

本文主要是介绍Delegate 委派模式和代理模式strategy的区别?策略模式如何实现消除多层if else?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

@[toc]

委派模式

委派模式,可以精简程序逻辑,提升代码的可读性。
委派模式(Delegate Pattern)的基本作用就是负责任务的调用和分配任务。
例如:老板(Boss)给项目经理(Leader)下达任务,项目经理会根据实际情况给每个员工派发工作任务,待员工把工作任务完成之后,再由项目经理汇报工作进度和结果给老板。
在这里插入图片描述

和代理模式的区别

跟代理模式很像,可以看做是一种特殊情况下的静态代理的全权代理,但是代理模式注重过程,而委派模式注重结果。委派模式在Spring 中应用非常多,常用的DispatcherServlet 其实就是用到了委派模式。

案例

在这里插入图片描述

public interface IEmployee {
    void doing(String command);
}

public class EmployeeA implements IEmployee {
    @Override
    public void doing(String command) {
        System.out.println("我是员工A,我现在开始干" + command + "工作");
    }
}

```java
public class EmployeeB implements IEmployee {
    @Override
    public void doing(String command) {
        System.out.println("我是员工B,我现在开始干" + command + "工作");
    }
}
public class Leader implements IEmployee {
    private Map<String, IEmployee> targets = new HashMap<>();

    public Leader() {
        targets.put("登录", new EmployeeA());
        targets.put("加密", new EmployeeB());
    }

    @Override
    public void doing(String command) {
        targets.get(command).doing(command);
    }
}
public class Boss {
    public void command(String command, Leader leader) {
        leader.doing(command);
    }
}

测试:

public class DelegateTest {
	public static void main(String[] args) {
	//客户请求(Boss)、委派者(Leader)、被被委派者(Target)
	//委派者要持有被委派者的引用
	//代理模式注重的是过程, 委派模式注重的是结果
	//策略模式注重是可扩展(外部扩展),委派模式注重内部的灵活和复用
	//委派的核心:就是分发、调度、派遣
	//委派模式:就是静态代理和策略模式一种特殊的组合
	new Boss().command("登录",new Leader());
	new Boss().command("加密", new Leader());
	}
}

在这里插入图片描述

应用场景

手写一个DispatcherServlet: DispatcherServlet根据url分配到对应的controller的method方法就体现了委派模式。

public class DispatcherServlet extends HttpServlet {


    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            doDispatch(req, resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String uri = request.getRequestURI();

        String mid = request.getParameter("mid");

        if ("/getMemberById".equals(uri)) {
            new MemberController().getMemberById(mid);
        } else if ("/getOrderById".equals(uri)) {
            new OrderController().getOrderById(mid);
        } else if ("/logout".equals(uri)) {
            new SystemController().logout();
        } else {
            response.getWriter().write("404 Not Found!!");
        }

    }
public class MemberController {

    public void getMemberById(String mid){
        System.out.println(mid);
    }

}

public class OrderController {

    public void getOrderById(String mid){
    }

}
public class SystemController {

    public void logout(){

    }

}

策略模式

介绍

在这里插入图片描述
策略模式(Strategy Pattern)是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。
在这里插入图片描述

策略模式的应用场景
1、假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。
2、一个系统需要动态地在几种算法中选择一种。
在这里插入图片描述

案例1。

课程经常会有优惠活动,优惠策略会有很多种可能
如:领取优惠券抵扣、返现促销、拼团优惠。下面我们用代码来模拟,首先我们创建一
个促销策略的抽象PromotionStrategy

在这里插入图片描述

public interface PromotionStrategy {
    void doPromotion();
}
/**
 * 返现活动
 * Created by HFL
 */
public class CashbackStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("返现促销,返回的金额转到支付宝账号");
    }
}

/**
 * 优惠券
 * 
 */
public class CouponStrategy implements PromotionStrategy {

    @Override
    public void doPromotion() {
        System.out.println("领取优惠券,课程的价格直接减优惠券面值抵扣");
    }
}
/**
 * 无优惠
 *
 */
public class EmptyStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("无促销活动");
    }
}

/**
 * 拼团优惠
 *
 */
public class GroupbuyStrategy implements PromotionStrategy{

    @Override
    public void doPromotion() {
        System.out.println("拼团,满20人成团,全团享受团购价");
    }
}

优惠活动

public class PromotionActivity {
    private PromotionStrategy promotionStrategy;
    public PromotionActivity(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }
    public void execute(){
        promotionStrategy.doPromotion();
    }
}

测试1:

public class PromotionActivityTest {
    public static void main(String[] args) {
        PromotionActivity activity618 = new PromotionActivity(new CouponStrategy());
        PromotionActivity activity1111 = new PromotionActivity(new CashbackStrategy());

        activity618.execute();
        activity1111.execute();
    }

在这里插入图片描述
根据前端的条件选择哪种策略方式:

   public static void main(String[] args) {
        PromotionActivity promotionActivity = null;
        String promotionKey = "CASHBACK";
        if(StringUtils.equals(promotionKey,"COUPON")){
            promotionActivity = new PromotionActivity(new CouponStrategy());
        }else if(StringUtils.equals(promotionKey,"CASHBACK")){
            promotionActivity = new PromotionActivity(new CashbackStrategy());
        }//......
        promotionActivity.execute();
    }

从形式上看,这这个测试类根据条件,类似简单工厂。所以我们可以改成简单工厂的方法优化下:
再写个简单工厂类.用于生产策略类:

public class PromotionStrategyFactory {
    private static Map<String,PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<String, PromotionStrategy>();
    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.COUPON,new CouponStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.CASHBACK,new CashbackStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.GROUPBUY,new GroupbuyStrategy());
    }

    private static final PromotionStrategy NON_PROMOTION = new EmptyStrategy();
    private PromotionStrategyFactory(){}

    public static PromotionStrategy getPromotionStrategy(String promotionKey){
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
        return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
    }
    private interface PromotionKey{
        String COUPON = "COUPON";
        String CASHBACK = "CASHBACK";
        String GROUPBUY = "GROUPBUY";
    }
}

重写测试类:

  public static void main(String[] args) {
        String promotionKey = "GROUPBUY";
        PromotionActivity promotionActivity = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
        promotionActivity.execute();
    }

在这里插入图片描述

案例2:订单支付策略案例

在这里插入图片描述

/**
 * 支付渠道
 * .
 */
public abstract class Payment {

    //支付类型
    public abstract String getName();

    //查询余额
    protected abstract double queryBalance(String uid);

    //扣款支付
    public MsgResult pay(String uid, double amount) {
        if(queryBalance(uid) < amount){
            return new MsgResult(500,"支付失败","余额不足");
        }
        return new MsgResult(200,"支付成功","支付金额:" + amount);
    }


}
public class JDPay extends Payment {

    public String getName() {
        return "京东白条";
    }

    protected double queryBalance(String uid) {
        return 500;
    }
}
public class AliPay extends Payment {

    public String getName() {
        return "支付宝";
    }

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

}

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 256;
    }

}

策略类(最重要)

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

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

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

    public static Payment get(String payKey) {
        if (!payStrategy.containsKey(payKey)) {
            return payStrategy.get(DEFAULT_PAY);
        }
        return payStrategy.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;
    }

    public String toString(){
        return ("支付状态:[" + code + "]," + msg + ",交易详情:" + data);
    }
}

测试:

public class PayStrategyTest {

    public static void main(String[] args) {

        //省略把商品添加到购物车,再从购物车下单
        //直接从点单开始
        Order order = new Order("1","20180311001000009",324.45);

        //开始支付,选择微信支付、支付宝、银联卡、京东白条、财付通
        //每个渠道它支付的具体算法是不一样的
        //基本算法固定的
        MsgResult pay = order.pay(PayStrategy.JD_PAY);
        //这个值是在支付的时候才决定用哪个值
//        System.out.println(order.pay(PayStrategy.ALI_PAY));
        System.out.println(pay);


        //java中的应用
//        Arrays.sort();
        //Resource
//        InstantiationStrategy
    }

}


在这里插入图片描述

切换成支付宝支付:
只要改一个参数:

MsgResult pay = order.pay(PayStrategy.JD_PAY);

在这里插入图片描述

策略模式在JDK 源码中的体现

Arrays 类的parallelSort 方法等

compare()方法,就是一个策略抽象实现.

public class Arrays {
public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> cmp) {
}
}
public interface Comparator<T> {
int compare(T o1, T o2);
}

策略模式的优缺点

优点:
1、策略模式符合开闭原则。
2、避免使用多重条件转移语句,如if…else…语句、switch 语句
3、使用策略模式可以提高算法的保密性和安全性。
缺点:
1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
2、代码中会产生非常多策略类,增加维护难度。

委派模式与策略模式综合应用

刚才的委派模式中的dispatchsevlet:实际项目中一定不止这几个Controller,往往是成千上万个Controller,显然,我们不能写成千上万个if…else… 。那么我们如何来改造呢,用策略模式:

public class DispatcherServlet extends HttpServlet {

    private List<Handler> handlerMapping = new ArrayList<Handler>();
    @Override
    public void init() throws ServletException {
        try {
            Class<?> memberControllerClass = MemberController.class;
            handlerMapping.add(new Handler()
                    .setController(memberControllerClass.newInstance())
                    .setMethod(memberControllerClass.getMethod("getMemberById", new Class[]{String.class}))
                    .setUrl("/web/getMemberById.json"));
        } catch (Exception e) {

        }
    }
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            doDispatch(req, resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws IOException {

        //1、获取用户请求的url
        //   如果按照J2EE的标准、每个url对对应一个Serlvet,url由浏览器输入
        String uri = request.getRequestURI();

        //2、Servlet拿到url以后,要做权衡(要做判断,要做选择)
        //   根据用户请求的URL,去找到这个url对应的某一个java类的方法

        //3、通过拿到的URL去handlerMapping(我们把它认为是策略常量)
        Handler handle = null;
        for (Handler h : handlerMapping) {
            if (uri.equals(h.getUrl())) {
                handle = h;
                break;
            }
        }
        //4、将具体的任务分发给Method(通过反射去调用其对应的方法)
        Object object = null;
        try {
            object = handle.getMethod().invoke(handle.getController(), request.getParameter("mid"));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //5、获取到Method执行的结果,通过Response返回出去
        response.getWriter().write("");
    }


    class Handler {

        private Object controller;
        private Method method;
        private String url;

        public Object getController() {
            return controller;
        }

        public Handler setController(Object controller) {
            this.controller = controller;
            return this;
        }

        public Method getMethod() {
            return method;
        }

        public Handler setMethod(Method method) {
            this.method = method;
            return this;
        }

        public String getUrl() {
            return url;
        }

        public Handler setUrl(String url) {
            this.url = url;
            return this;
        }
    }

}

总结:
1.使用委派模式,可以写出更加优雅的代码。
2.策略模式,可以消除程序中大量的冗余代码和多重条件转移语句。
3.委派模式属于行为型模式,基本作用就是负责任务的调度和分配任务,跟代理模式很像,可以看做是一种特殊情况下的静态代理的全权代理,但是代理模式注重过程,而委派模式注重结果。
4.策略模式是行为型模式:(Strategy Pattern)是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。可以避免多重分支的if…else…和switch语句.


谢谢大家支持

这篇关于Delegate 委派模式和代理模式strategy的区别?策略模式如何实现消除多层if else?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!