策略模式-实例(登录类设计)
面试被问到:使用“开闭原则”、“面向对象”的思想,设计一个登录类,涉及账号密码登录、手机号码登录什么的
当时(现在也)觉得是策略模式的应用,但是具体怎么写就…
现在来实现一遍
Round.1
首先我们设计了一个顶级父类Login
,然后分别用两个子类("账号密码登录类"和"手机验证码登录类"来继承它)
为什么这里一开始是用继承而不是用接口呢?
因为有一些公共的代码实现,比如logout()
方法需要复用,完全每必要重写
/** * 登录类顶级父类 * @author yao 2022/12/8 */ public abstract class Login { /** * 登录 */ abstract void login(); /** * 注销 */ void logout(){ System.out.println("用户注销,退出登录"); } }
/** * 账号密码登录 * @author yao 2022/12/8 */ public class AccountLogin extends Login{ @Override public void login() { System.out.println("使用账号密码登录"); } }
/** * 手机号码登录 * @author yao 2022/12/8 */ public class PhoneNumberLogin extends Login{ @Override void login() { System.out.println("使用手机号码验证码登录"); } }
目前看来还行,我可以使用多态来调用
/** * @author yao 2022/12/8 */ public class TestLogin { public static void main(String[] args) { Login login = new AccountLogin(); login.login(); login.logout(); login = new PhoneNumberLogin(); login.login(); } }
使用账号密码登录
用户注销,退出登录
使用手机号码验证码登录
Round.2
然后变化来了:来了一个部分子类有,部分子类没有的方法
更进一步,不仅部分子类有,部分子类没有,有该方法的对象执行该方法的表现还不一样
举个例子,比如:注册
注册只有“手机验证码登录”和“账号密码登录类”有,因为这两个是自己管理的,但是调用第三方认证的登录类比如“QQ登录”是没有的
不确定这个例子是否足够好
那么矛盾就出来了:
- 如果直接修改超类,添加一个方法?
显然是不合适的,因为不是每个子类都应该有这个方法
覆盖成空实现?
听起来做法很蠢,要检查每一个不符合的方法,然后都覆盖一遍?!随着子类越来越多这是无法忍受而且极易出错的
直接改动原来的代码也是不符合“开闭原则”的
- 把超类改成接口?
似乎也是不合适的,和上面一样,不是每个子类都需要实现这个方法 - 那考虑把有些子类有、有些子类没的方法再抽象成接口?
这样的话对于共有的代码逻辑,比如logout()
,就不得不在每一个子类中写一遍,不优雅不满足代码复用
设计原则:
把会变化的部分取出来并封装起来,以便以后可以轻易地改动或扩充此部分,而不影响不需要变化的其他部分
在这里会变化的就是对象的行为,即注册
把注册抽象为接口,同时为这个接口提供不同的实现
顶级父类添加这个接口对象替代原来的方法
并且对具体的实现也不是自己完成,而是委托给接口对象
Register register; /** * 不亲自处理注册逻辑,而是委托给接口对象 */ public void performRegister(){ register.register(); }
然后子类可以在构造方法中按需实例化这个接口对象,不同的实例
public PhoneNumberLogin(){ register = new PhoneRegister(); }
但是这样是有问题的,如果我调用了我本不应该有的行为,因为没有实例化对象,会报空指针异常的
改进成在顶级父类中提供set()
方法设置接口对象,这样虽然可以动态设置,但是没办法保证一定被设置
…烦,又乱了
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/articles/16965920.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步