当前位置: 首页 > news >正文

基于开闭原则重构 CRM 图表系统基于单一职责原则重构登录模块

基于开闭原则重构 CRM 图表系统

背景

原 CRM 图表系统中,图表类型(柱状图、饼图、折线图等)的渲染逻辑耦合在一个大方法或类中,每增加一种图表类型就需要修改核心代码,违反开闭原则(对扩展开放,对修改关闭)。

重构前(反例)

typescript

// 反例:每增加图表类型都要修改 ChartRenderer class ChartRenderer { render(type: string, data: any) { if (type === 'bar') { // 渲染柱状图逻辑 console.log('渲染柱状图', data); } else if (type === 'pie') { // 渲染饼图逻辑 console.log('渲染饼图', data); } else if (type === 'line') { // 渲染折线图逻辑 console.log('渲染折线图', data); } // 新增图表 → 需要增加 else if,修改原有类 } }

重构后(符合开闭原则)

  • 定义抽象图表接口Chart

  • 每种图表实现该接口

  • 使用工厂或依赖注入管理图表实例

  • 新增图表只需新建实现类,无需修改已有代码

typescript

// 图表抽象接口 interface Chart { render(data: any): void; } // 柱状图实现 class BarChart implements Chart { render(data: any): void { console.log('渲染柱状图', data); } } // 饼图实现 class PieChart implements Chart { render(data: any): void { console.log('渲染饼图', data); } } // 折线图实现 class LineChart implements Chart { render(data: any): void { console.log('渲染折线图', data); } } // 新增雷达图(扩展开放) class RadarChart implements Chart { render(data: any): void { console.log('渲染雷达图', data); } } // 图表渲染器(对修改关闭) class ChartRenderer { private chart: Chart; constructor(chart: Chart) { this.chart = chart; } render(data: any): void { this.chart.render(data); } } // 可选:图表工厂,用于根据类型创建(但工厂模式本身也符合开闭原则,可通过配置映射避免修改) class ChartFactory { private static registry: Map<string, new () => Chart> = new Map(); static register(type: string, ctor: new () => Chart) { this.registry.set(type, ctor); } static create(type: string): Chart { const Ctor = this.registry.get(type); if (!Ctor) throw new Error(`未知图表类型: ${type}`); return new Ctor(); } } // 注册已知图表 ChartFactory.register('bar', BarChart); ChartFactory.register('pie', PieChart); ChartFactory.register('line', LineChart); // 新增图表只需调用 register('radar', RadarChart),不改动原有逻辑 // 使用示例 const barChart = ChartFactory.create('bar'); const renderer = new ChartRenderer(barChart); renderer.render({ sales: [100, 200] });

要点

  • 图表接口Chart作为抽象层,依赖倒置。

  • 新增图表不需要修改ChartRendererChartFactory(工厂通过注册机制扩展)。

  • 符合开闭原则:系统对扩展开放(可注册新图表),对修改关闭(核心流程不变)。


基于单一职责原则重构登录模块

背景

原登录模块一个类/函数承担了过多职责:输入验证、用户认证、会话管理、日志记录、错误处理等,导致代码臃肿、难以测试和维护。

重构前(反例)

java

// 反例:一个类承担了多个职责 public class LoginService { public boolean login(String username, String password) { // 1. 输入校验 if (username == null || username.trim().isEmpty()) { throw new IllegalArgumentException("用户名不能为空"); } if (password == null || password.length() < 6) { throw new IllegalArgumentException("密码长度不足"); } // 2. 数据库认证 User user = database.findUserByUsername(username); if (user == null || !user.getPassword().equals(encrypt(password))) { return false; } // 3. 创建会话 String sessionId = UUID.randomUUID().toString(); sessionStore.put(sessionId, user); // 4. 记录日志 logger.info("用户 " + username + " 登录成功,session: " + sessionId); // 5. 发送欢迎邮件(意外职责) emailService.sendWelcome(user.getEmail()); return true; } }

重构后(符合单一职责原则)

将不同职责分离到独立的类/模块中:

  • LoginValidator:负责输入校验

  • AuthenticationService:负责用户认证

  • SessionManager:负责会话创建和管理

  • LoginAuditLogger:负责日志记录

  • 可选:LoginSuccessHandler处理登录成功后的附加动作(如发送邮件)

java

// 1. 职责:输入校验 class LoginValidator { public void validate(String username, String password) { if (username == null || username.trim().isEmpty()) { throw new IllegalArgumentException("用户名不能为空"); } if (password == null || password.length() < 6) { throw new IllegalArgumentException("密码长度不足"); } } } // 2. 职责:用户认证 interface AuthenticationService { User authenticate(String username, String password) throws AuthException; } class DatabaseAuthenticationService implements AuthenticationService { private UserRepository userRepository; private PasswordEncoder passwordEncoder; @Override public User authenticate(String username, String password) { User user = userRepository.findByUsername(username); if (user == null || !passwordEncoder.matches(password, user.getPasswordHash())) { throw new AuthException("用户名或密码错误"); } return user; } } // 3. 职责:会话管理 class SessionManager { private Map<String, User> sessionStore = new ConcurrentHashMap<>(); public String createSession(User user) { String sessionId = UUID.randomUUID().toString(); sessionStore.put(sessionId, user); return sessionId; } // 可扩展其他会话操作:销毁、验证等 } // 4. 职责:登录日志记录 class LoginAuditLogger { public void logSuccess(String username, String sessionId) { LoggerFactory.getLogger(getClass()).info("用户 {} 登录成功,session: {}", username, sessionId); } public void logFailure(String username, String reason) { LoggerFactory.getLogger(getClass()).warn("用户 {} 登录失败: {}", username, reason); } } // 5. 可选:登录成功后的附加动作处理器(遵循开闭原则) interface LoginSuccessHandler { void onSuccess(User user, String sessionId); } class WelcomeEmailHandler implements LoginSuccessHandler { private EmailService emailService; @Override public void onSuccess(User user, String sessionId) { emailService.sendWelcome(user.getEmail()); } } // 最终组装:登录门面或协调者(只负责协调,不实现具体逻辑) class LoginFacade { private LoginValidator validator; private AuthenticationService authService; private SessionManager sessionManager; private LoginAuditLogger auditLogger; private List<LoginSuccessHandler> successHandlers; // 可以注入多个 public LoginResult login(String username, String password) { try { validator.validate(username, password); User user = authService.authenticate(username, password); String sessionId = sessionManager.createSession(user); auditLogger.logSuccess(username, sessionId); for (LoginSuccessHandler handler : successHandlers) { handler.onSuccess(user, sessionId); } return LoginResult.success(sessionId); } catch (IllegalArgumentException | AuthException e) { auditLogger.logFailure(username, e.getMessage()); return LoginResult.failure(e.getMessage()); } } }

要点

  • 每个类只负责一项明确的职责,变更原因只有一个。

  • LoginFacade仅做流程编排,不包含具体业务逻辑。

  • 认证方式(数据库、LDAP、OAuth)可通过AuthenticationService接口灵活替换。

  • 登录成功后的附加行为通过LoginSuccessHandler扩展,不修改核心流程,也符合开闭原则。


总结

原则重构对象核心手法收益
开闭原则CRM 图表系统定义抽象接口Chart,具体图表实现接口,使用工厂+注册表扩展新增图表无需修改原有类,降低风险
单一职责原则登录模块将输入校验、认证、会话、日志、附加动作分离到独立类提高可读性、可测试性,降低耦合
http://www.zskr.cn/news/1512521.html

相关文章:

  • 2026广州工厂实用新型专利深度测评|生产设备/工装夹具/精密治具/模具辅助组件专利申请、结构优化、AI同质化筛查规避、初审实质审查风控、工厂专属配套代理服务机构TOP3 - 信息热点
  • Windows和Office激活难题终极解决方案:KMS智能激活工具完整指南
  • 别再死记硬背了!用Wireshark抓包实战,5分钟搞懂TCP确认与重传机制
  • 深度解析 kill-douyin-watermark-online:如何优雅实现短视频无水印提取
  • 2026 上海屋顶防水公司综合实力 TOP5 排行榜(6月最新)排名 - 信息热点
  • 景观水质护理之道:智能转鼓过滤技术的突破实践 - 资讯报道
  • 武汉亮化工程选择指南:众晨光电一体化服务如何解决行业难题 - 资讯报道
  • 游击队灌浆当时好、后来漏:青岛防水行业这个坑,99%业主踩过 - 青岛防水品牌推荐
  • 基于MCF523x eTPU的机器人运动控制系统设计与实践
  • 电脑文件管理zs 2026年6月12日
  • 微信投票零基础制作方法,2026 正规免费平台实操指南 - 信息热点
  • Java作业:创建线程的两种方式对比(Thread子类 vs Runnable接口)
  • 2026年武汉手表回收市场现状解析及服务机构综合梳理 - 奢品屋武汉奢侈品回收
  • 微信聊天记录导出终极指南:简单三步永久备份你的数字记忆
  • 2026包装机行业标杆齐聚!超声波/阀口/干粉砂浆全品类领跑者揭秘 - 信息热点
  • 别再只看跑分了!聊聊那些真正影响你NVMe SSD游戏加载和文件拷贝速度的隐藏因素
  • 南京复读学校排名,提分实力派汇总 - 信息热点
  • AB Download Manager:重新定义高效下载管理的终极解决方案
  • MOOTDX:Python通达信数据接口终极指南,5分钟解决量化投资数据难题
  • CRP (174-185) ;IYLGGPFSPNVL
  • 北京性价比高的西装店 - 中媒介
  • AI Agent 在自动化测试中的落地实践:从“脚本执行”到“智能测试工程师”
  • 2026杭州抖音代运营公司榜单:极具实力的金牌服务商深度测评 - 信息热点
  • 别踩2026年录音生成会议纪要工具选型坑 过来人实测整理各类工具成本对比经验
  • OpenPLC:开源工业控制器的革命性选择
  • 江苏低分考生复读优选,南京头部复读学校排名盘点 - 信息热点
  • 3分钟搞定缠论分析:ChanlunX通达信插件完整指南
  • 专访|广州企业布局AI流量怎么选靠谱GEO公司?业内专家给出标准答案 - 信息热点
  • 2026广州各区发明专利布局指南|高含金量专利挖掘、技术交底文件优化、分区差异化布局策略,优质专利代理机构推荐TOP3 - 信息热点
  • 关于动态规划【力扣96.不同的二叉搜索树的递推公式怎么理解?】