1.课程学习目标
1.掌握委派模式,精简程序逻辑,提升代码的可读性。
2.通过学习策略模式来消除程序中大量的if..else.. 和switch语句。
3.深刻理解策略模式的应用场景,提高算法的保密性和安全性。
2.内容定位
1.希望通过对于委派模式的学习,让自己写出更加优雅代码的人群。
2.希望通过策略模式的学习,来消除程序中大量的冗余代码和多重条件转移语句的人群。
3.委派模式详解
3.1委派模式的定义
1.委派模式(Delegate Pattern) 的基本作用就是负责任务的调度和分配,和代理模式很像,可以看做是一种特殊情况下的静态代理的全权代理,但是代理模式注重过程,而委派模式注重结果。
2.不属于GOF 23种设计模式之一。
3.属于行为型模式。
4.Delegate 结尾的一般都是委派模式,Dispatcher
3.2 demo案例
3.2.1模拟Boss指派任务给Leader 由员工完成任务执行
main
/**
* @PackageName: com.raven.pattern.delegate.simple
* @ClassName: SimpleTest
* @Blame: raven
* @Date: 2021-08-01 14:07
* @Description: 委派模式简单案例 模仿BOSS下达指令给leader BOSS不关心到底具体由谁再干活 只需要让leader完成任务即可
* leader不直接自己干活,而根据任务的特点 ,调用不同的employee 进行执行任务
*/
public class SimpleTest {
public static void main(String[] args) {
Boss boss = new Boss();
boss.execute("JAVA",new Leader());
boss.execute("GO",new Leader());
}
}
定义boss类 leader类
public class Boss {
public void execute(String command , Leader leader){
leader.doCommand(command);
}
}
/**
* @PackageName: com.raven.pattern.delegate.simple
* @ClassName: Leader
* @Blame: raven
* @Date: 2021-08-01 10:42
* @Description: leader知道每一个员工所擅长的语言,当有需求到达时,根据需求要求的语言,交于不同的员工进行开发任务。
*/
public class Leader {
private static Map<String, IEmployee> employeeMap = new HashMap<>();
private static String JAVA = "JAVA";
private static String GO = "GO";
private static String DEFAULT = JAVA;
static {
employeeMap.put(JAVA, new EmployeeA());
employeeMap.put(GO, new EmployeeB());
}
public void doCommand(String command) {
if (!employeeMap.containsKey(command)) {
employeeMap.get(DEFAULT).doing(command);
} else {
employeeMap.get(command).doing(command);
}
}
}
定义员工类
/**
* @PackageName: com.raven.pattern.delegate.simple
* @ClassName: IEmplyee
* @Blame: raven
* @Date: 2021-08-01 10:44
* @Description: 定义员工接口 规范员工行为
*/
public interface IEmployee {
/**
* 员工可以干活
* @param command 命令行为
*/
void doing(String command);
}
/**
* @PackageName: com.raven.pattern.delegate.simple
* @ClassName: EmployeeA
* @Blame: raven
* @Date: 2021-08-01 10:39
* @Description:
*/
public class EmployeeA implements IEmployee{
@Override
public void doing(String command) {
System.out.println("我是员工,A我擅长JAVA,我执行" + command + "命令");
}
}
/**
* @PackageName: com.raven.pattern.delegate.simple
* @ClassName: EmployeeB
* @Blame: raven
* @Date: 2021-08-01 10:39
* @Description:
*/
public class EmployeeB implements IEmployee{
@Override
public void doing(String command){
System.out.println("我是员工B,我擅长GO,我执行" + command + "命令");
}
}
3.2.2 模拟spring mvc dispatchServlet 根据不同的uri 执行不同的controller代码
disptacherServlet
/**
* @PackageName: com.raven.pattern.delegate.mvc
* @ClassName: DispatcherServlet
* @Blame: raven
* @Date: 2021-08-01 14:22
* @Description: 模拟手写mvc dispatcherServlet 委派设计模式
* <p>
* 模拟 根据不同的uri 调用不同的controller方法
*/
public class DispatcherServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 完成调度
doDispatch(req, resp);
}
/**
* 委派模式 将服务调用的事情委派给dispatch
* 通过dispatch 完成调度,根据请求不同的uri 调用不同controller代码 执行业务逻辑
*
* @param req
* @param resp
* @throws IOException
*/
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String requestURI = req.getRequestURI();
String mid = req.getParameter("mid");
if (StringUtils.equals("getOrderById", requestURI)) {
new OrderController().getOrderById(mid);
} else if (StringUtils.equals("getUserById", requestURI)) {
new UserController().getUserById(mid);
} else if (StringUtils.equals("logout", requestURI)) {
new SystemController().logout();
} else {
resp.getWriter().write("404 not found !");
}
}
}
controller
public class OrderController {
public void getOrderById(String id){
System.out.println("获取订单详情!");
}
}
public class UserController {
public void getUserById(String mid){
System.out.println("获取用户信息!");
}
}
public class SystemController {
public void logout(){
System.out.println("退出服务器!");
}
}
3.3 spring中的委派模式
BeanDefinitionParserDelegate
4.策略模式详解
4.1策略模式的定义
1.策略模式(Stratege pattern) 是指定义了算法家族、分别封装起来,让他们之间可以互相转换,此模式让算法的变化不会影响到使用算法的用户。
2.可以避免多重分支的if..else.. 和switch语句。
4.2策略模式的适用场景
1.加入系统中有很多类,而他们的区别仅仅在于他们的行为不同
2.一个系统需要动态地在几种算法中选择一种。
4.3策略模式优点
1.策略模式符合开闭原则。
2.避免使用多重条件转移语句,如if .. else..语句、switch语句。
3.使用策略模式可以提高算法的保密性和安全性。
4.4策略模式的缺点
1.客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
2.代码中会产生非常多的策略类,增加维护难度。
4.5策略模式案例Demo
4.5.1模拟选购商品不同活动采用不同的优惠策略
活动main
/**
* @PackageName: com.raven.pattern.strategy.promotion
* @ClassName: PromotionActivityTest
* @Blame: raven
* @Date: 2021-08-01 16:14
* @Description: 创建促销活动 指定活动名称 根据不同的活动名称返回不同的促销活动内容
*/
public class PromotionActivityTest {
public static void main(String[] args) {
/**
* 避免了if else 判断不同活动使用不同策略 促销活动工厂内部决定返回促销策略
*/
PromotionActivity promotionActivity618 = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategyByPromotionKey(""));
promotionActivity618.execute();
PromotionActivity promotionActivity1111 = new PromotionActivity(PromotionStrategyFactory.getPromotionStrategyByPromotionKey("返现活动"));
promotionActivity1111.execute();
}
}
/**
* @PackageName: com.raven.pattern.strategy.promotion
* @ClassName: PromotionActivity
* @Blame: raven
* @Date: 2021-08-01 15:54
* @Description: 定义促销活动,每一场促销活动都需要指定促销策略
*/
public class PromotionActivity {
private IPromotionStrategy promotionStrategy;
public PromotionActivity(IPromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
}
public void execute() {
promotionStrategy.doPromotion();
}
}
策略工厂
/**
* @PackageName: com.raven.pattern.strategy.promotion
* @ClassName: IPromotionStratrgy
* @Blame: raven
* @Date: 2021-08-01 15:50
* @Description: 定义营销活动策略规范
*/
public interface IPromotionStrategy {
/**
* 执行促销活动
*/
void doPromotion();
}
public class GroupbuyStrategy implements IPromotionStrategy {
@Override
public void doPromotion() {
System.out.println("促销活动为团购活动,五人一起团购,每人减400元!");
}
}
public class EmptyStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("现在没有活动!");
}
}
public class CashbackStrategy implements IPromotionStrategy{
@Override
public void doPromotion() {
System.out.println("促销活动为返现活动,返现200元!");
}
}
/**
* @PackageName: com.raven.pattern.strategy.promotion
* @ClassName: PromotionStrategyFactory
* @Blame: raven
* @Date: 2021-08-01 15:56
* @Description: 促销活动工厂 懒汉式单例模式 + 策略模式
*/
public class PromotionStrategyFactory {
private PromotionStrategyFactory() {
}
private static PromotionStrategyFactory factory;
private static Map<String, IPromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
static {
factory = new PromotionStrategyFactory();
PROMOTION_STRATEGY_MAP.put(PromotionKeyEnum.CASH_BACK.getPromotionName(), new CashbackStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKeyEnum.GROUP_BUY.getPromotionName(), new GroupbuyStrategy());
}
public static PromotionStrategyFactory getFactory() {
return factory;
}
/**
* 根据促销活动名称返回促销活动内容
* @param promotionName
* @return
*/
public static IPromotionStrategy getPromotionStrategyByPromotionKey(String promotionName) {
IPromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionName);
return Objects.isNull(promotionStrategy) ? new EmptyStrategy() : promotionStrategy;
}
}
public enum PromotionKeyEnum {
EMPTY("无活动"),
GROUP_BUY("团购活动"),
CASH_BACK("返现活动")
;
@Getter
private String promotionName;
PromotionKeyEnum(String promotionName) {
this.promotionName = promotionName;
}
}
4.5.2根据不同的支付方式进行不同的支付策略
支付main
/**
* @PackageName: com.raven.pattern.strategy.pay
* @ClassName: OrderPayTest
* @Blame: raven
* @Date: 2021-08-01 17:05
* @Description: 模拟用户使用不同支付方式支付订单
* 根据用户选择的支付方式不同,调用不同的支付体系完成支付操作
*/
public class OrderPayTest {
public static void main(String[] args) {
Order order = new Order("0001", "OR00001", 90);
MsgResult msgResult = order.pay(PayStrategy.WE_CHAT_PAY);
System.out.println(msgResult);
System.out.println("====================");
Order order2 = new Order("0001", "OR00002", 90);
MsgResult msgResult2 = order2.pay(PayStrategy.ALI_PAY);
System.out.println(msgResult2);
}
}
/**
* @PackageName: com.raven.pattern.strategy.pay
* @ClassName: Order
* @Blame: raven
* @Date: 2021-08-01 16:43
* @Description: 订单对象 支付时调用支付接口
*/
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;
}
/**
* 订单支付 不同支付方式返回不同支付策略
* @param payType
* @return
*/
public MsgResult pay(String payType) {
Payment payment = PayStrategy.getPayment(payType);
System.out.println("欢迎使用" + payment.getName() + "支付");
System.out.println("支付订单号为:" + orderId);
System.out.println("本次交易金额为" + amount + "元");
return payment.pay(uid, amount);
}
}
/**
* @PackageName: com.raven.pattern.strategy.pay
* @ClassName: MsgResult
* @Blame: raven
* @Date: 2021-08-01 16:45
* @Description: 支付结果封装
*/
public class MsgResult {
private int code;
private String msg;
private Object data;
public MsgResult(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
@Override
public String toString() {
return "支付状态:" + "[" + code + "], " + msg + ", 交易详情:" + data;
}
}
支付策略
/**
* @PackageName: com.raven.pattern.strategy.pay.payport
* @ClassName: PayStrategy
* @Blame: raven
* @Date: 2021-08-01 16:57
* @Description: 支付策略类 根据不同的支付方式封装返回不同的支付策略
*/
public class PayStrategy {
private PayStrategy() {
}
public static final String ALI_PAY = "支付宝支付";
public static final String WE_CHAT_PAY = "微信支付";
private static Map<String, Payment> PAYMENT_MAP = new HashMap<>();
static {
PAYMENT_MAP.put(ALI_PAY, new AliPay());
PAYMENT_MAP.put(WE_CHAT_PAY, new WechatPay());
}
public static Payment getPayment(String payType) {
return PAYMENT_MAP.getOrDefault(payType, new AliPay());
}
}
public class AliPay extends Payment {
@Override
public String getName() {
return "支付宝支付";
}
@Override
public double queryBalance(String uid) {
return 100;
}
}
public class WechatPay extends Payment {
@Override
public String getName() {
return "微信支付";
}
@Override
public double queryBalance(String uid) {
return 10;
}
}
public abstract class Payment {
/**
* 获取支付方式名称
* @return
*/
public abstract String getName();
/**
* 查询账户余额
* @param uid
* @return
*/
public abstract double queryBalance(String uid);
/**
* 支付校验 当账号余额不足时,无法完成支付
* @param uid
* @param amount
* @return
*/
public MsgResult pay(String uid, double amount) {
if (queryBalance(uid) < amount) {
return new MsgResult(500, "支付失败", "余额不足!");
}
return new MsgResult(200, "支付成功", "支付金额:" + amount);
}
}
4.6 基于策略模式重写 DispatcherServlet
/**
* @PackageName: com.raven.pattern.delegate.mvc
* @ClassName: DispatcherServlet
* @Blame: raven
* @Date: 2021-08-01 14:22
* @Description: 模拟手写mvc dispatcherServlet 委派设计模式
* <p>
* 模拟 根据不同的uri 调用不同的controller方法
*/
public class DispatcherServlet extends HttpServlet {
/**
* 通过工厂模式将controller封装到List集合中
*/
private List<Handler> handlerMapping = Lists.newArrayList();
/**
* 初始化mapping
* 通过反射将所有的实体属性封装到List中
*
* @throws ServletException
*/
@Override
public void init() throws ServletException {
Class<OrderController> orderClazz = OrderController.class;
try {
handlerMapping.add(new Handler(orderClazz.newInstance(),
orderClazz.getMethod("getOrderById", String.class),
"getOrderById"
));
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 完成调度
// doDispatch(req, resp);
doDispatch2(req, resp);
}
/**
* 通过反射执行根据不同的url 执行不同的controller中的策略
* @param req
* @param resp
*/
private void doDispatch2(HttpServletRequest req, HttpServletResponse resp) {
String requestURI = req.getRequestURI();
String mid = req.getParameter("mid");
Handler handler = null;
for (Handler h : handlerMapping) {
if (StringUtils.equals(requestURI, h.getUrl())) {
handler = h;
break;
}
}
try {
Object o = handler.getMethod().invoke(handler.getController(), mid);
resp.getWriter().write(o.toString());
} catch (IllegalAccessException | InvocationTargetException | IOException e) {
e.printStackTrace();
}
}
@Data
class Handler {
private Object controller;
private Method method;
private String url;
public Handler(Object controller, Method method, String url) {
this.controller = controller;
this.method = method;
this.url = url;
}
}
}
4.7spring中的策略模式
InstantiationStrategy、Resource