一、策略模式
策略模式定义了一系列的算法,把它们一个个封装起来, 并且使它们可相互替换,让算法的变化不会影响到使用算法的用户。 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。使用策略模式还可以消除大量的if...else...
。符合开闭原则。
1、普通策略模式
支付接口:
/**
* 支付的抽象
*/
public interface Payment {
String getName();
int queryBalance();
default void pay(int payMoney) {
if (queryBalance() >= payMoney) {
System.out.println("使用" + getName() + ", 支付了" + payMoney + "元, 支付成功!");
} else {
System.out.println("使用" + getName() + ", 支付失败, 余额不足!");
}
}
}
阿里支付:
public class AliPay implements Payment{
@Override
public String getName() {
return "阿里支付";
}
@Override
public int queryBalance() {
return 5000;
}
}
银联支付:
public class UnionPay implements Payment {
@Override
public String getName() {
return "银联支付";
}
@Override
public int queryBalance() {
return 100;
}
}
微信支付:
public class WeChatPay implements Payment{
@Override
public String getName() {
return "微信支付";
}
@Override
public int queryBalance() {
return 250;
}
}
空的支付方式:
public class NoPay implements Payment {
@Override
public String getName() {
return "没有这种支付方式";
}
@Override
public int queryBalance() {
return 0;
}
}
订单类:
/**
* 策略模式的入口
*/
public class Order {
private Payment payment;
public void pay(Payment payment, int money) {
payment.pay(money);
}
}
测试代码:
Order order = new Order();
order.pay(new AliPay(), 200);
order.pay(new UnionPay(), 101);
order.pay(new NoPay(), 100);
测试结果:
这种策略模式必须要求客户端知道具体的策略实现类,如果使用通过约定参数来指定算法策略的话,那使用这种普通的策略模式也免不了使用if-else结构的代码。不过使用策略模式+工厂模式可以完美消除if-else结构的代码。
2、策略模式+工厂模式
将订单类改为如下,其他的类都不变:
/**
* 策略模式的入口
*/
public class Order {
private Payment payment;
private static Map<String, Payment> pay = new HashMap<>();
static {
pay.put(PAY.AliPay.name, new AliPay());
pay.put(PAY.UnionPay.name, new UnionPay());
pay.put(PAY.WeChatPay.name, new WeChatPay());
pay.put(PAY.DefaultPay.name, new NoPay());
/*
pay.put(Pay.ALIPAY, new AliPay());
pay.put(Pay.UNIONPAY, new UnionPay());
pay.put(Pay.WECHATPAY, new WeChatPay());
pay.put(Pay.DEFAULTPAY, new NoPay());
*/
}
//使用内部接口方式定义常量
interface Pay {
String ALIPAY = "阿里支付";
String UNIONPAY = "银联支付";
String WECHATPAY = "微信支付";
String DEFAULTPAY = "没有这种支付方式";
}
//使用枚举方式定义常量
enum PAY {
AliPay("阿里支付"), UnionPay("银联支付"), WeChatPay("微信支付"), DefaultPay("没有这种支付方式");
String name;
PAY(String name) {
this.name = name;
}
}
public void pay(String payName, int money) {
this.payment = pay.get(payName) == null ? pay.get(PAY.DefaultPay.name) : pay.get(payName);
this.payment.pay(money);
}
public void pay(Payment payment, int money) {
payment.pay(money);
}
}
测试代码:
Order order = new Order();
order.pay("阿里支付", 200);
order.pay("银联支付", 101);
测试结果:
二、DispatchServlet的简单模拟
使用委派模式模拟SpringMVC的委派机制。使用一个类绑定了请求URI、控制器、请求方法。
会员控制器:
public class MemberController {
public Object getMemberById(int id) {
return null;
}
}
订单控制器:
public class OrderController {
public Object getOrderById(int id) {
return null;
}
}
dispatchServlet:
/**
* SpringMVC的委派模式就是通过DispatcherServlet将请求的URI转为不同的java代码
*/
public class DispatcherServlet extends HttpServlet {
private List<Handler> handlerMapping = new LinkedList<>();
@Override
public void init() throws ServletException {
try {
handlerMapping.add(new Handler().setUri("/web/getMemberById").setController(MemberController.class.newInstance()).setMethod(MemberController.class.getMethod("getMemberById", int.class)));
handlerMapping.add(new Handler().setUri("/web/getOrderById").setController(OrderController.class.newInstance()).setMethod(OrderController.class.getMethod("getOrderById", int.class)));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doDispatcher(req, resp);
}
/**
* 使用策略模式去掉多个if-else判断
*/
private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) {
String requestURI = req.getRequestURI();
Handler h = null;
for (Handler handler : handlerMapping) {
if (Objects.equals(handler.getUri(), requestURI)) {
h = handler;
break;
}
}
try {
h.getMethod().invoke(h.getController(), Integer.parseInt(req.getParameter("mid")));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
class Handler {
String uri;
Object controller;
Method method;
//修改set方法为函数式编程
public String getUri() {
return uri;
}
public Handler setUri(String uri) {
this.uri = uri;
return this;
}
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;
}
}
}