策略模式(Strategy)
定义一系列的算法,把他们一个个封装起来,并且使他们可相互替换。策略模式使得算法可独立于使用它的客户而变化。
在GoF23种设计模式中,属于行为型模式( Behavioral Patterns)
。
策略模式将不同的算法聚合起来,提供了统一的策略接口。将策略的选择权交给客户端动态选择,
- 优点
- 符合开闭原则,新增算法不会影响之前的算法逻辑
- 减少
if-else
的使用,因为可以用抽象接口统一表示算法对象 - 高内聚低耦合
- 缺点
- 需要客户端需要了解不同策略
- 增加了对象数目,不同的策略
- 使用场景
- 系统需要动态选择几种算法来实现功能
实例
角色说明
- Strategy
- 策略接口
- ConcreteStrategy
- 具体算法
- Context
- 策略应用逻辑,用于维护对Strategy对象的引用
- Client
- 使用者
举例
以打折活动为例。两家店铺进行打折,一家打折策略是全场85折,另一家是满300减120。
角色说明
- DiscountStrategy(Strategy)
- 打折策略
- Discount85(ConcreteStrategy)
- 全场85折
- Full300Reduce120(ConcreteStrategy)
- 满300减120
- DiscountActivity(Context)
- 打折活动
- Client
code
- DiscountStrategy.java
public interface DiscountStrategy {
void doStrategy();
}
- Discount85.java
public class Discount85 implements DiscountStrategy{
@Override
public void doStrategy() {
System.out.println("打折啦,全场85折!!!");
}
}
- Full300Reduce120.java
public class Full300Reduce120 implements DiscountStrategy{
@Override
public void doStrategy() {
System.out.println("打折啦,满300减120!!!");
}
}
- DiscountActivity.java
public class DiscountActivity {
private DiscountStrategy discountStrategy;
public DiscountActivity(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
public void doActivity() {
discountStrategy.doStrategy();
}
}
- Client.java
public class Client {
public static void main(String[] args) {
DiscountActivity discountActivity;
System.out.println("店铺A:");
discountActivity = new DiscountActivity(new Discount85());
discountActivity.doActivity();
System.out.println("店铺B:");
discountActivity = new DiscountActivity(new Full300Reduce120());
discountActivity.doActivity();
}
}
- output
店铺A:
打折啦,全场85折!!!
店铺B:
打折啦,满300减120!!!
思考
这里的店铺A、店铺B实际开发中应该都是接口处动态传参过来的。客户端要决定使用那种策略还需要if-else
判断。
因此,避免多重判断,我们可以使用简单工程模式,建立工厂时,我们还可以通过单例模式和享元模式静态初始化所有具体策略类。
如果不想手写静态初始化代码,我们还可以通过Spring 动态扫描接口实现类,实现动态加载,具体操作如下。
- 动态加载代码
Map<String, DiscountStrategy> map = SpringContextHolder.getApplicationContext().getBeansOfType(DiscountStrategy.class);
- SpringContextHolder.java
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
synchronized (SpringContextHolder.class) {
SpringContextHolder.applicationContext = applicationContext;
}
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContext.getBean(name);
}
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<T> clazz) {
checkApplicationContext();
return applicationContext.getBean(clazz);
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext未注入,请在application-context.xml中定义SpringContextHolder");
}
}
}
实例
code:com.google.common.hash.BloomFilterStrategies
角色说明
- BloomFilter.Strategy(Strategy)
- BloomFilterStrategies.MURMUR128_MITZ_32(ConcreteStrategy)
- BloomFilterStrategies.MURMUR128_MITZ_64(ConcreteStrategy)
- com.google.common.hash.BloomFilter#create(com.google.common.hash.Funnel<? super T>, long, double)(Context)
- com.google.common.hash.BloomFilter(Clinet)
该处策略模式采用了枚举单例模式,布隆过滤器的具体实现打算以后再详看。
补充:Bloom Filter是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合。
总结
策略模式是日常开发中最为常见的模式。可简单理解为接口的封装与使用。需要注意的是,策略模式与其他模式的结合使用,如:工厂模式、享元模式等。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名,转载请标明出处
最后编辑时间为:
2019-12-17