概念
在计算机编程中,策略模式是一种行为 软件设计模式,可以在运行时选择算法。代码不是直接实现单个算法,而是接收关于在一系列算法中使用哪些算法的运行时指令。
举例
策略模式可以说是一种选择,它会根据调用者的属性去调用对应的算法,动态地改变对象的行为,用户可以调正对应的策略达到想要的目的。下面会举一个策略模式的Demo场景,同时将分析 Spring 中的策略模式。
组成
Context:一般提供setStrategy(strategy),用于设置对应的策略,同时起到封装的作用,屏蔽直接访问实际策略。
Srategy:strategy公共接口,规定了策略的属性,方法
ConcreteStrategy:实际策略类,实现了接口,根据具体策略实现对应的算法。
举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| /** * Created by Heiku on 2018/7/31 * * Strategy pattern */
// 策略接口 购买手机的客户 interface Client{ void introduct(); }
// 果粉 class AppleFans implements Client{ @Override public void introduct() { System.out.println("向果粉介绍苹果新产品"); } }
// 游戏玩家 class Gamer implements Client{
@Override public void introduct() { System.out.println("向手机玩家介绍 黑鲨等游戏手机"); } }
// 学生党 class Student implements Client{ @Override public void introduct() { System.out.println("向学生党介绍最新发布的手机"); } }
// 手机城 public class PhoneShop { private Client client = null;
public void setClient(Client client) { this.client = client; }
public void introduct(){ client.introduct(); }
public static void main(String[] args) { PhoneShop shop = new PhoneShop();
// 果粉进店 System.out.println("果粉进店"); shop.setClient(new AppleFans()); shop.introduct();
// 游戏发烧友进店 System.out.println("游戏发烧友进店"); shop.setClient(new Gamer()); shop.introduct();
// 学生党进店 System.out.println("学生党进店"); shop.setClient(new Student()); shop.introduct(); } }
// 结果 果粉进店 向果粉介绍苹果新产品 游戏发烧友进店 向手机玩家介绍 黑鲨等游戏手机 学生党进店 向学生党介绍最新发布的手机
|
Spring中的实际应用
在 SpringMVC中,当启动服务器时,request进来时,DispatcherSerlvet作为请求入口,会依次调用HttpServletBean -> FrameworkServlet -> DispatcherServlet,完成容器的初始化,注意几个servlet是向上的继承关系.
在FrameworkServlet中会调用 initWebApplicationContext()-> onRefresh()
1 2 3 4 5 6
| protected WebApplicationContext initWebApplicationContext() { ... if (!this.refreshEventReceived) { this.onRefresh(wac); } ...
|
接着,在DispatcherServlet时,会进行bean的初始化,调用onRefresh() -> initStrategies(),进行九大组件的初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| // 刷新容器时,将策略更新 protected void onRefresh(ApplicationContext context) { this.initStrategies(context); }
// 进行初始化策略 protected void initStrategies(ApplicationContext context) { this.initMultipartResolver(context); this.initLocaleResolver(context); this.initThemeResolver(context); this.initHandlerMappings(context); this.initHandlerAdapters(context); this.initHandlerExceptionResolvers(context); this.initRequestToViewNameTranslator(context); this.initViewResolvers(context); this.initFlashMapManager(context); }
|
根据context上下文,获取对应策略
1 2 3 4 5 6 7 8 9
| // 获取对应策略 protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) { List<T> strategies = this.getDefaultStrategies(context, strategyInterface); if (strategies.size() != 1) { throw new BeanInitializationException("DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]"); } else { return strategies.get(0); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { String key = strategyInterface.getName(); String value = defaultStrategies.getProperty(key); if (value == null) { return new LinkedList(); } else { String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List<T> strategies = new ArrayList(classNames.length); String[] var7 = classNames; int var8 = classNames.length;
for(int var9 = 0; var9 < var8; ++var9) { String className = var7[var9]; try { Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); Object strategy = this.createDefaultStrategy(context, clazz); strategies.add(strategy); } catch (ClassNotFoundException var13) { throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var13); } catch (LinkageError var14) { throw new BeanInitializationException("Error loading DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]: problem with class file or dependent class", var14); } }
return strategies; } }
|