设计模式主要有23种,大致可分为三类:创建型,机构行,行为型;具体如下:
创建型
1,单例设计模式
2,工厂设计模式
3,建造者设计模式
4,原型设计模式
结构型
5,代理设计模式
6,桥接设计模式
7,装饰设计模式
8,适配器设计模式
9,外观设计模式
10,享元设计模式
11,组合设计模式
行为型
持续更新....
策略设计模式
简介(定义)
策略模式定义了一系列的算法,并将每一个算法封装起来,而且是它们还可以互相替换。策略模式可以使算法的变化独立于使用它们的客户端(这里的客户端代指使用算法的代码)。
使用场景
1,针对同一类型问题的多种处理方式,仅仅具体行为有差别时;
2,需要安全的封装多种同一类型的操作时;
3,出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时;
使用
根据客户端如何选用那种策略,可分为两种:1,编译时静态确定;2,运行时动态确定;
一,编译时静态确定
编译时静态确定:在编译或者写代码时已经确定使用那种策略;通过一个例子具体解释可能更好理解;
例如:我们出行不同的交通方式,产生的费用也不一样;就是价格计算方式不一样,不同的交通费用计算,可以看作不同的策略;
策略的抽象
public interface CalculateStrategy {
//按距离计算价格,km公里,return放回价格
int calculatePrice(int km);
}
具体策略
public class BusStrategy implements CalculateStrategy {
@Override
public int calculatePrice(int km) {
//有些地方公交上车就是2块
return 2;
}
}
public class SubwayStrategy implements CalculateStrategy {
//3公里以内2元,3到6公里3;6到9公里4块,9到12公里5块,12到15公里6块,其他7块;
@Override
public int calculatePrice(int km) {
if (km < 3) {
return 2;
} else if (3 < km && km < 6) {
return 3;
}else if (6 < km && km < 9) {
return 4;
}else if (9 < km && km < 12) {
return 5;
}else if (12 < km && km < 15) {
return 6;
}
return 7;
}
}
策略的创建及使用
public class UserCalculator {
public static void main(String[] args) {
UserCalculator calculator = new UserCalculator();
calculator.setStrategy(new BusStrategy());//在编译期已经确定是那种策略,本例已经确定乘坐公交出行;
System.out.println("公交车程8公里的价格:"+calculator.calculatePrice(8));
}
CalculateStrategy mStrategy;
public void setStrategy(CalculateStrategy mStrategy) {
this.mStrategy = mStrategy;
}
public int calculatePrice(int km) {
return mStrategy.calculatePrice(km);
}
}
二,运行时动态确定
运行时动态确定指的是,我们事先并不知道会使用哪个策略,而是在程序运行期间,根据配置、用户输入、计算结果等不确定参数或因素,动态决定使用哪种策略。
1,策略的定义
策略类的定义比较简单,包含一个策略接口和一组实现这个接口的策略类。因为所有的策略类都实现相同的接口,所以,客户端代码基于接口而非实现编程,可以灵活地替换不同的策略。
public interface CalculateStrategy {
//按距离计算价格,km公里,return放回价格
int calculatePrice(int km);
}
public class BusStrategy implements CalculateStrategy {
@Override
public int calculatePrice(int km) {
//有些地方公交上车就是2块
return 2;
}
}
public class SubwayStrategy implements CalculateStrategy {
//3公里以内2元,3到6公里3;6到9公里4块,9到12公里5块,12到15公里6块,其他7块;
@Override
public int calculatePrice(int km) {
if (km < 3) {
return 2;
} else if (3 < km && km < 6) {
return 3;
}else if (6 < km && km < 9) {
return 4;
}else if (9 < km && km < 12) {
return 5;
}else if (12 < km && km < 15) {
return 6;
}
return 7;
}
}
2,策略的创建
因为策略模式会包含一组策略,在使用它们的时候,一般会通过类型(type)来判断创建哪个策略来使用。为了封装创建逻辑,我们需要对客户端代码屏蔽创建细节。我们可以把根据 type 创建策略的逻辑抽离出来,放到工厂类中。
public class StrategyFactory {
private static final Map<String,CalculateStrategy> strategies = new HashMap<>();
public static final String BUS = "bus";
public static final String SUBWAY = "subway";
static {
strategies.put(BUS, new BusStrategy());
strategies.put(SUBWAY, new SubwayStrategy());
}
public static CalculateStrategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
return strategies.get(type);
}
}
一般来讲,如果策略类是无状态的,不包含成员变量,只是纯粹的算法实现,这样的策略对象是可以被共享使用的,不需要在每次调用 getStrategy() 的时候,都创建一个新的策略对象。针对这种情况,我们可以使用上面这种工厂类的实现方式,事先创建好每个策略对象,缓存到工厂类中,用的时候直接返回。
相反,如果策略类是有状态的,根据业务场景的需要,我们希望每次从工厂方法中,获得的都是新创建的策略对象,而不是缓存好可共享的策略对象,那我们就需要按照如下方式来实现策略工厂类。
public class StrategyFactory {
public static final String BUS = "bus";
public static final String SUBWAY = "subway";
public static CalculateStrategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
if (type.equals(BUS)) {
return new BusStrategy();
} else if (type.equals(SUBWAY)) {
return new SubwayStrategy();
}
return null;
}
}
3,策略的使用
public class UserCalculator {
public static void main(String[] args) {
try {
Properties props = new Properties();
props.load(new FileInputStream("./config.properties"));
String type = props.getProperty("eviction_type");
CalculateStrategy evictionStrategy = StrategyFactory.getStrategy(type);
UserCalculator userCalculator = new UserCalculator();
userCalculator.setStrategy(evictionStrategy);
System.out.println("8公里交通费价格:" + userCalculator.calculatePrice(8));
} catch (IOException e) {
e.printStackTrace();
}
}
CalculateStrategy mStrategy;
public void setStrategy(CalculateStrategy mStrategy) {
this.mStrategy = mStrategy;
}
public int calculatePrice(int km) {
return mStrategy.calculatePrice(km);
}
}
main方法也可以改为独立的类
public class Application {
public void calcultor() {
Properties props = new Properties();
props.load(new FileInputStream("./config.properties"));
String type = props.getProperty("eviction_type");
CalculateStrategy evictionStrategy = StrategyFactory.getStrategy(type);
UserCalculator2 userCalculator = new UserCalculator2();
userCalculator.setStrategy(evictionStrategy);
System.out.println("8公里交通费价格:" + userCalculator.calculatePrice(8));
}
}
如何利用策略模式避免分支判断?
在这个例子中,我们没有使用策略模式,而是将策略的定义、创建、使用直接耦合在一起。
public class OrderService {
public double discount(Order order) {
double discount = 0.0;
OrderType type = order.getType();
if (type.equals(OrderType.NORMAL)) { // 普通订单
// ...省略折扣计算算法代码
} else if (type.equals(OrderType.GROUPON)) { // 团购订单
// ...省略折扣计算算法代码
} else if (type.equals(OrderType.PROMOTION)) { // 促销订单
// ...省略折扣计算算法代码
}
return discount;
}
}
我们使用策略模式对上面的代码重构,将不同类型订单的打折策略设计成策略类,并由工厂类来负责创建策略对象。具体的代码如下所示:
public interface DiscountStrategy {
double calDiscount(Order order);
}
// 省略NormalDiscountStrategy、GrouponDiscountStrategy、PromotionDiscountStrategy类代码...
// 策略的创建
public class DiscountStrategyFactory {
private static final Map strategies = new HashMap<>();
static {
strategies.put(OrderType.NORMAL, new NormalDiscountStrategy());
strategies.put(OrderType.GROUPON, new GrouponDiscountStrategy());
strategies.put(OrderType.PROMOTION, new PromotionDiscountStrategy());
}
public static DiscountStrategy getDiscountStrategy(OrderType type) {
return strategies.get(type);
}
}
// 策略的使用
public class OrderService {
public double discount(Order order) {
OrderType type = order.getType();
DiscountStrategy discountStrategy = DiscountStrategyFactory.getDiscountStrategy(type);
return discountStrategy.calDiscount(order);
}
}