接着可以将注册逻辑拆解为注册处理器和使用注册处理器的service模块:
/** * @Author linhao * @Date created in 7:56 上午 2021/9/3 */ public interface IRegisterService { /** * 用户注册之后处理函数 * * @param registerInputParam 用户注册之后的传入参数 */ void postProcessorAfterRegister(RegisterInputParam registerInputParam); }
注册处理器内部才是真正的核心部分:
/** * @Author linhao * @Date created in 8:10 上午 2021/9/3 */ public abstract class AbstractRegisterHandler { /** * 获取注册渠道ID * * @return */ public abstract int getSource(); /** * 注册之后的核心通知模块程序 * * @param registerInputParam * @return */ public abstract boolean doPostProcessorAfterRegister(RegisterInputParam registerInputParam); }
具体的实现交给了各个Handler组件:
公众号注册渠道的后置处理器
/** * @Author linhao * @Date created in 8:16 上午 2021/9/3 */ public class GZHRegisterHandler extends AbstractRegisterHandler { @Override public int getSource() { return RegisterConstants.RegisterEnum.GZH_CHANNEL.getCode(); } @Override public boolean doPostProcessorAfterRegister(RegisterInputParam registerInputParam) { System.out.println("公众号处理逻辑"); return true; } }
app注册渠道的后置处理器
/** * @Author linhao * @Date created in 8:16 上午 2021/9/3 */ public class AppRegisterHandler extends AbstractRegisterHandler { @Override public int getSource() { return RegisterConstants.RegisterEnum.APP_CHANNEL.getCode(); } @Override public boolean doPostProcessorAfterRegister(RegisterInputParam registerInputParam) { System.out.println("app处理逻辑"); return true; } }
不同的注册渠道号通过一个枚举来进行管理:
public class RegisterConstants { public enum RegisterEnum{ GZH_CHANNEL(0,"公众号渠道"), APP_CHANNEL(1,"app渠道"); RegisterEnum(int code, String desc) { this.code = code; this.desc = desc; } int code; String desc; public int getCode() { return code; } } }
接下来,对于注册的后置处理服务接口进行实现:
/** * @Author linhao * @Date created in 7:48 上午 2021/9/3 */ public class RegisterServiceImpl implements IRegisterService { private static List<AbstractRegisterHandler> registerHandlerList = new ArrayList<>(); static { registerHandlerList.add(new GZHRegisterHandler()); registerHandlerList.add(new AppRegisterHandler()); } @Override public void postProcessorAfterRegister(RegisterInputParam registerInputParam) { for (AbstractRegisterHandler abstractRegisterHandler : registerHandlerList) { if(abstractRegisterHandler.getSource()==registerInputParam.getSource()){ abstractRegisterHandler.doPostProcessorAfterRegister(registerInputParam); return; } } throw new RuntimeException("未知注册渠道号"); } }
最后通过简单的一段测试程序:
public class Test { public static void main(String[] args) { RegisterInputParam registerInputParam = new RegisterInputParam(); registerInputParam.setUserId(10012); registerInputParam.setSource(0); IRegisterService registerService = new RegisterServiceImpl(); registerService.postProcessorAfterRegister(registerInputParam); RegisterInputParam registerInputParam2 = new RegisterInputParam(); registerInputParam2.setUserId(10013); registerInputParam2.setSource(1); registerService.postProcessorAfterRegister(registerInputParam2); System.out.println("======="); } }
这样的设计和起初最先前的设计相比有几处不同的完善点:
新增不同注册渠道的时候,只需要关心注册渠道的source参数。
同时对于后续业务的拓展,新增不同的注册渠道的时候,RegisterServiceImpl只需要添加新编写的注册处理器类即可。
再回过头来看,这样的一段代码设计是否满足了开放封闭原则呢?
每次新增不同的注册类型处理逻辑之后,程序中都只需要新增一种Handler处理器,这种处理器对于原先的业务代码并没有过多的修改,从整体设计的角度来看,并没有对原有的代码结构造成影响,而且灵活度相比之前有所提高。这也正好对应了,对扩展开放,对修改关闭。
如果你对设计模式有一定了解的话,可能还会发现大多数常用的设计模式都在遵守这一项原则,例如模版模式,策略模式,责任链模式等等。
里氏替换原则
我认为,里氏替换原则更多是体现在了父子类继承方面,强调的是子类在继承了父类对象的时候不应该破坏这个父类对象的设计初衷。
举个例子来说:
我们定义了一个提款的服务:
/** * @Author linhao * @Date created in 11:21 上午 2021/9/4 */ public interface DrawMoneyService { /** * 提款函数 * * @param drawMoneyInputParam */ void drawMoney(DrawMoneyInputParam drawMoneyInputParam); }
对应的是一个抽象实现父类:
/** * @Author linhao * @Date created in 11:25 上午 2021/9/4 */ public abstract class AbstractDrawMoneyServiceImpl implements DrawMoneyService{ /** * 设计初衷,需要对提现金额进行参数校验 * * @param drawMoneyInputParam */ @Override public abstract void drawMoney(DrawMoneyInputParam drawMoneyInputParam); }