7大原则
- 单一职责原则:一个类负责一项职责
- 里氏替换原则:继承与派生的规则
- 依赖倒置原则:高层模块不应该依赖底层模块,二者都应该依赖其抽象;抽象不应该依赖其细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程
- 接口隔离原则:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少
- 迪米特法则:低耦合,高内聚
- 开闭原则:一个软件实体和类、模块和函数应该对扩展开放,对修改关闭。
- 组合/聚合复用原则:尽量使用组合和聚合少使用继承的关系来达到复用的原则。
策略模式原型举例
现在要实现一个算税策略,税计算类型有价内税和价外税,将来可能会增加新的税类型,初始设计类结构如下
- TaxStrategy: 税策略接口
- IntegerTaxStrategy: 价内税策略,负责计算价内税
- OuterTaxStrategy: 价外税策略,负责计算价外税
- TaxType: 谁类型定义,当前只有价内税和价外税
- TaxStrategyFactory: 税策略工厂,根据税类型获取不同的税策略来算税
代码实现
1. 税策略代码
public interface TaxStrategy {
double calc(long amount);
}
class InterTaxStrategy implements TaxStrategy {
@Override
public double calc(long amount) {
System.out.println("内税计算中");
// 获取税率
final double taxRate = 0.2;
return amount * taxRate;
}
}
class OuterTaxStrategy implements TaxStrategy {
@Override
public double calc(long amount) {
System.out.println("外税计算中");
// 获取税率
final double taxRate = 0.2;
return amount / (1 + taxRate) * taxRate;
}
}
// 税类型定义
enum TaxType {
INTER, OUTER
}
2. IF语句实现的税策略工厂
public class TaxStrategyFactory {
public static TaxStrategy getTaxStrategy(TaxType taxType) throws Exception {
// 当增加新的税类型时,需要修改代码,同时会增加圈复杂度
if (taxType == TaxType.INTER) {
return new InterTaxStrategy();
} else if (taxType == TaxType.OUTER) {
return new OuterTaxStrategy();
} else {
throw new Exception("The tax type is not supported");
}
}
}
如果通过if语句来获取不同的税策略,当增加新的税策略时就不得不修改已有代码,当算税方法很多时,就不那么好看,同时也增加了圈复杂度
圈复杂度:也称为条件复杂度,是一种衡量代码复杂度的标准,其符号为V(G)。
麦凯布最早提出一种称为“基础路径测试”的软件测试方法,测试程序中的每一线性独立路径,所需的测试用例个数即为程序的圈复杂度。
圈复杂度可以用来衡量一个模块判定结构的复杂程度,其数量上表现为独立路径的条数,也可理解为覆盖所有的可能情况最少使用的测试用例个数。
圈复杂度可应用在程序的子程序、模块、方法或类别。
3.税策略工厂中使用Map代替if
public class MapTaxStrategyFactory {
// 存储税策略
static Map<TaxType, TaxStrategy> taxStrategyMap = new HashMap<>(16, 0.75F);
// 注册默认税策略
static {
registerTaxStrategy(TaxType.INTER, new InterTaxStrategy());
registerTaxStrategy(TaxType.OUTER, new OuterTaxStrategy());
}
// 提供税注册策略接口,外部只需要调用此接口接口新增税策略,而无需修改策略工厂内部代码
public static void registerTaxStrategy(TaxType taxType, TaxStrategy taxStrategy) {
taxStrategyMap.put(taxType, taxStrategy);
}
// 通过map获取税策略,当增加新的税策略时无需修改代码,对修改封闭,对扩展开放,遵循开闭原则
public static TaxStrategy getTaxStrategy(TaxType taxType) throws Exception {
// 当增加新的税类型时,需要修改代码,同时增加圈复杂度
if (taxStrategyMap.containsKey(taxType)) {
return taxStrategyMap.get(taxType);
} else {
throw new Exception("The tax type is not supported.");
}
}
}
可以看到,进化后IF语句没有了,减少了圈复杂度,增加新的策略后只需调用策略注册接口就好了,不需要修改获取税策略的代码
业务中的应用
比如,有些业务中,我们会将付费和退费放在同一个接口中,而如何区分是付费还是退费,我们会根据一个支付状态来区分。一般情况下,我们会根据if判断,但是如何当这个接口中支付状态越来越多的时候,我们会写很多的if-else if。这样的话,代码看起来就会很别扭。所以,在此情况下,我们可以使用策略模式来加以修改代码,优化代码