@[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语句.
个人微信公众号:
搜索: 怒放de每一天
不定时推送相关文章,期待和大家一起成长!!
完
谢谢大家支持~