场景一、各处取值判断逻辑不统一,精度不统一,最终结果不一样导致的bug
获取一个人的label属性, 其属性具有时效性
之前:
// 实体类
@Data
public class Person {
private Integer label;
private Date labelLimit;
}
public class ServiceTest {
// 获取 Person的label属性, 存在时效性, 过期则不展示
public static void main(String[] args) {
Person person = new Person();
person.setLabel(2);
person.setLabelLimit(new Date());
// `代码一`
// 使用Date 类判断是否有效,精确到时分秒
Integer rawLabel1 = null;
if (new Date().before(person.getLabelLimit())) {
rawLabel = person.getLabel();
}
// `代码二`
// 使用LocalDate判断是否有效,可以精确到日
Integer rawLabel2 = null;
LocalDate limit = person.getLabelLimit().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
if (LocalDate.now().isBefore(limit)) {
rawLabel2 = person.getLabel();
}
// 等等等等
// 代码一、二 出出现在多处使用 甚至还会有其他写法
}
}
进行规整统一:
// label属性 访问接口
public interface LabelAccess {
// label属性是否还有效
boolean valid();
// 若属性有效返回属性
Integer getLabel();
}
// person包装类, 实现LabelAccess接口
public class PersonWrapper implements LabelAccess {
private Person person;
// 需要传入person实例构造函数
public PersonWrapper(Person person) {
this.person = person;
}
@Override
public boolean valid() {
return new Date().before(person.getLabelLimit());
}
@Override
public Integer getLabel() {
if (!valid()) {
return null;
}
return person.getLabel();
}
}
public class ServiceTest {
public static void main(String[] args) {
Person person = new Person();
person.setLabel(2);
person.setLabelLimit(new Date());
// 改造后
LabelAccess labelAccess = new PersonWrapper(person);
Integer label = labelAccess.getLabel();
}
}
场景二、某个方法多处调用,但是每个场景前戏略微有所差别
调用方控制校验逻辑, 又想要代码复用
public class FlowService {
// 根据id 创建数据并保存到数据库
static void createStep(Long id) {
// todo 保存数据
}
}
public class ServiceTest {
// 场景一
public static void call1() {
// 需要进行 “校验一”
boolean f1 = true;
if (!f1) {
throw new RuntimeException("校验一不通过");
}
FlowService.createStep(1L);
}
// 场景二
public static void call2() {
// 需要进行 “校验二”
boolean f2 = true;
if (!f2) {
throw new RuntimeException("校验二不通过");
}
FlowService.createStep(2L);
}
// 场景三
public static void call3() {
// 先进行 “校验一”
boolean f1 = true;
if (!f1) {
throw new RuntimeException("校验一不通过");
}
// 再进行 “校验二”
boolean f2 = true;
if (!f2) {
throw new RuntimeException("校验二不通过");
}
FlowService.createStep(3L);
}
}
弊端在于校验一二逻辑如果多次使用需要多次编写,容易出错,且不好复用,后续需求变动也难以应对,所以 使用策略模式改造
// 抽象基类
public abstract class CreateStepChecker {
public Long id;
public void setId(Long id) {
this.id = id;
};
abstract public void check();
}
// “校验一” 的逻辑, 只需要重写check方法
public class CreateStepCheckerOne extends CreateStepChecker {
@Override
public void check() {
System.out.println(id);
// 校验一
boolean f1 = true;
if (!f1) {
throw new RuntimeException("校验一不通过");
}
}
}
// “校验二” 的逻辑, 只需要重写check方法
public class CreateStepCheckerTwo extends CreateStepChecker {
@Override
public void check() {
System.out.println(id);
// 校验二
boolean f2 = true;
if (!f2) {
throw new RuntimeException("校验二不通过");
}
}
}
// 略微修改createStep方法, 允许传入多个CreateStepChecker
public class FlowService {
static void createStep(Long id, CreateStepChecker... checkers) {
// 进行校验
for (CreateStepChecker checker : checkers) {
checker.setId(id);
checker.check();
}
// todo 保存数据
}
}
public class ServiceTest {
// 调用方根据实际需要传入 CreateStepChecker 的实现类
public static void call1() {
FlowService.createStep(1L, new CreateStepCheckerOne());
}
public static void call2() {
FlowService.createStep(2L, new CreateStepCheckerTwo());
}
public static void call3() {
FlowService.createStep(3L, new CreateStepCheckerOne(), new CreateStepCheckerTwo());
}
}