委派模式
概述
委派模式(Delegate Pattern)的基本目的就是负责任务的调用和分配,和代理模式很像,可以看成是一个特殊的静态代理的全权代理,但是代理模式注重过程,委派模式注重结果。委派模式不是GOF23种设计模式。现实生活中也时常有委派的场景发生,比如老板(Boss)下达命令,部门经理(Manager)把具体任务分配给员工(Employee),待员工完成工作再由经理汇报进度和情况给老板。我们用代码模拟一下这个场景
员工接口
public interfaceIEmployee {voiddoing(String command);
}
员工A
public class EmployeeA implementsIEmployee {
@Overridepublic voiddoing(String command) {
System.out.println("我是员工A,我正在做"+command);
}
}
员工B
public class EmployeeB implementsIEmployee {
@Overridepublic voiddoing(String command) {
System.out.println("我是员工B,我正在做"+command);
}
}
经理分发任务给员工
public classManager {private Map map = new HashMap();publicManager()
{
map.put("登录",newEmployeeA());
map.put("加密",newEmployeeB());
}voiddoing(String command)
{
IEmployee employee=map.get(command);
employee.doing(command);
}
}
老板下达命令
public classBoss {voidcommand(String command, Manager manager)
{
manager.doing(command);
}
}
可以看出经理分配任务生动体现了委派模式
下面我们来看一下在SpringMVC的DispatcherServlet中如何体现委派模式
业务类MemberController
public classMemberController {public voidgetMemberById(String mid)
{
}
}
OrderController
public classOrderController {public voidgetOrderById(String oid)
{
}
}
SystemController
public classSystemController {public voidlogin()
{
}
}
DispatcherServlet
public class DispatcherServletextends HttpServlet {
private voiddoDispatch(HttpServletRequest req, HttpServletResponse resp)throws IOException {
String uri = req.getRequestURI();
String id = req.getParameter("id");
if("getMemberById".equals(uri))
{
new MemberController().getMemberById(id);
}
else if ("getOrderById".equals(uri))
{
new OrderController().getOrderById(id);
}
else if("login".equals(uri))
{
new SystemController().login();
}
else
{
resp.getWriter().write("404 Not Found!!");
}
}
@Override
protected voidservice(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
doDispatch(req,resp);
}
}
web.xml
/p>
"http://java.sun.com/dtd/web-app_2_3.dtd" >
Archetype Created Web Application
delegateServlet
com.stu.pattern.delegate.mvc.DispatcherServlet
1
delegateServlet
/*
一个完整的委派模式就实现出来了
策略模式
策略模式(Strategy Pattern)定义了一系列算法,并且把每一个算法封装起来,使得每一个算法可以相互替代,把算法策略与客户端分离开来相互独立。
举个例子:去商场买东西碰到促销活动,那么活动有很多种比如优惠券抵扣活动、返现活动、拼团活动,下面是不使用策略模式的代码实现
促销管理类
public classPromotionManager {public voiddoPromotion(String sType)
{if("coupon".equals(sType))
{
System.out.println("领取优惠券直接抵扣");
}else if ("cashBack".equals(sType))
{
System.out.println("返现促销,返现金额到支付宝账号");
}else if ("groupBuy".equals(sType))
{
System.out.println("团购促销,满20人参加团购活动");
}
}
}
客户端调用
public classTest {public static voidmain(String[] args) {
PromotionManager promotionManager= newPromotionManager();
promotionManager.doPromotion("groupBuy");
}
}
测试发现上面的代码可以实现这样一个场景功能,可是代码是有问题的,我们发现促销管理类太过庞大和臃肿,当我们如果有一个别的促销增加时要修改促销管理类违背开闭原则
使用策略模式实现上面的促销
促销策略接口
public interfaceIPromotionStrategy {voiddoPromotion();
}
优惠券促销策略
public class CouponStrategy implementsIPromotionStrategy {
@Overridepublic voiddoPromotion() {
System.out.println("领取优惠券直接抵扣");
}
}
返现促销策略
public class CashBackStrategy implementsIPromotionStrategy {
@Overridepublic voiddoPromotion() {
System.out.println("返现促销,返现金额到支付宝账号");
}
}
团购优惠策略
public class GroupBuyStrategy implementsIPromotionStrategy {
@Overridepublic voiddoPromotion() {
System.out.println("团购促销,满20人参加团购活动");
}
}
促销活动方案接收具体策略
public classPromotionActivity {privateIPromotionStrategy promotionStrategy;publicPromotionActivity(IPromotionStrategy promotionStrategy) {this.promotionStrategy =promotionStrategy;
}public voiddoPromotion()
{this.promotionStrategy.doPromotion();
}
}
测试
public classPromotionStrategyTest {public static voidmain(String[] args) {
PromotionActivity promotionActivity= new PromotionActivity(newCashBackStrategy());
promotionActivity.doPromotion();
}
}
可以发现我们客户端需要确定使用哪一个算法即可调用促销活动具体的策略,当我们策略新增时我们只需要增加策略类即可比如我们现在要有一个打折策略
public class DiscountStrategy implementsIPromotionStrategy {
@Overridepublic voiddoPromotion() {
System.out.println("打折活动,折扣8折");
}
}
我们无需修改已经写好的策略,只需要新增类就好
策略模式理解
策略模式的作用:把具体的算法实现从业务逻辑中剥离出来,成为一系列独立算法类,使得它们可以相互替换。
策略模式的着重点:不是如何来实现算法,而是如何组织和调用这些算法,从而让我们的程序结构更加的灵活、可扩展。
可以发现我们不用策略模式会有很多的if和else if,这些逻辑其实是对立的是平等的每次只会走一个逻辑,这与策略模式不谋而合
策略模式的应用场景
系统中有很多类,他们的区别仅仅是行为不同
一个系统需要动态的在几种算法中选择一个
为了加深对策略模式的印象,我们在举个例子,我们都用过支付宝、微信支付、银联支付和京东支付。一个常见的应用场景就是大家在下单支付时会选择支付方式,如果用户未选择则会有一个默认的支付方式
抽象类支付策略
public abstract classPayment {//支付类型
public abstractString getName();//查询余额
public abstract doublequeryBalance(String uid);//支付扣款
public MsgResult pay(String uid,doubleamount)
{if(queryBalance(uid)
{return new MsgResult(500,"支付失败","余额不足");
}return new MsgResult(200,"支付成功","支付金额:"+amount);
}
}
返回结果类
public classMsgResult {private intcode;privateObject data;privateString msg;public MsgResult(intcode, Object data, String msg) {this.code =code;this.data =data;this.msg =msg;
}
@OverridepublicString toString() {return "支付状态:["+ code +"]," + msg + ",交易详情:"+data;
}
}
策略子类-Alipay
public class AliPay extendsPayment {
@OverridepublicString getName() {return "支付宝";
}
@Overridepublic doublequeryBalance(String uid) {return 500;
}
}
策略子类-JDPay
public class JDPay extendsPayment {
@OverridepublicString getName() {return "京东白条";
}
@Overridepublic doublequeryBalance(String uid) {return 500;
}
}
策略子类-UnionPay
public class UnionPay extendsPayment {
@OverridepublicString getName() {return "银联支付";
}
@Overridepublic doublequeryBalance(String uid) {return 2000;
}
}
策略子类-Alipay
public class WeChatPay extendsPayment {
@OverridepublicString getName() {return "微信支付";
}
@Overridepublic doublequeryBalance(String uid) {return 1000;
}
}
管理策略的类
public classPayStrategyManager {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 payStrategies = new HashMap<>();static{
payStrategies.put(ALI_PAY,newAliPay());
payStrategies.put(JD_PAY,newJDPay());
payStrategies.put(WECHAT_PAY,newWeChatPay());
payStrategies.put(UNION_PAY,newUnionPay());
}public staticPayment get(String key)
{if (!payStrategies.containsKey(key))returnpayStrategies.get(DEFAULT_PAY);returnpayStrategies.get(key);
}
}
订单类
public classOrder {privateString uid;privateString orderId;private doubleamount;public Order(String uid, String orderId, doubleamount) {this.uid =uid;this.orderId =orderId;this.amount =amount;
}publicMsgResult pay(String key)
{
Payment payment=PayStrategyManager.get(key);
System.out.println("欢迎使用" +payment.getName());
System.out.println("本次交易金额是:" + amount + "开始扣款");returnpayment.pay(uid,amount);
}publicMsgResult pay()
{returnpay(PayStrategyManager.DEFAULT_PAY);
}
}
客户端测试
public classPayTest {public static voidmain(String[] args) {
Order order= new Order("1","201801020558",500);
System.out.println(order.pay(PayStrategyManager.ALI_PAY));
}
}
测试结果
看下类图
通过不同的支付策略实现不同方式的支付
策略在JDK中的使用
说一个比较常用的比较器接口Comparator,我们常用的compare()方法
public interface Comparator{intcompare(T o1, T o2);
...
}
Comparator 抽象下面有非常多的实现类,我们经常会把 Comparator 作为参数传入作为排序策略,例如 Arrays 类的 parallelSort 方法等:
public static void parallelSort(T[] a, int fromIndex, inttoIndex,
Comparator super T>cmp) {
....
}
传入不同的排序策略,得到不同的结果
策略模式的优缺点
优点
符合开闭原则
避免使用多重if、else语句和switch
提高算法的保密性和安全性
缺点
客户端必须知道所有的策略,自己决定使用哪一种策略
代码中会出现很多的策略类,增加系统维护难度