软件设计原则详解:开闭原则、里氏替换原则、迪米特法则

张开发
2026/4/15 5:00:15 15 分钟阅读

分享文章

软件设计原则详解:开闭原则、里氏替换原则、迪米特法则
软件设计三大核心原则开闭里氏替换依赖倒置全网最细讲解附Java正反例面试必背在日常开发中你一定遇到过这些痛点加个小功能改出一堆Bug继承乱用逻辑越跑越偏换个数据库/组件要改几十处代码这些问题本质都是没遵守软件设计原则。今天就把面试工作最常用的三大核心设计原则讲透开闭原则、里氏替换原则、依赖倒置原则。全文配Java代码正反例看完就能用在项目里。前言设计原则不是玄学是前人总结的代码健壮性、可扩展、可维护的底层规律。今天讲的三大原则地位开闭原则OCP设计原则的核心里氏替换原则LSP继承的黄金标准依赖倒置原则DIP解耦的终极手段一、开闭原则 OCP1. 核心思想对扩展开放对修改关闭。扩展新增功能、新增类、新增实现关闭不修改已测试、已上线的稳定代码一句话能加就不加改能扩就不改旧。2. 为什么要遵守不改老代码 不引入新Bug系统更稳定、可维护性更强符合“高内聚低耦合”生活例子电脑USB接口。插U盘、鼠标、键盘不用拆电脑这就是开闭原则。3. 反例违反OCP// 绘制工具类用if-else判断类型违反开闭publicclassShapeDrawer{publicvoiddrawShape(StringshapeType){if(shapeType.equals(Circle)){System.out.println(绘制圆形);}elseif(shapeType.equals(Square)){System.out.println(绘制正方形);}}}问题加三角形必须加else if改老代码风险极高完全违反开闭原则4. 正例遵守OCPStep1定义抽象接口publicinterfaceShape{voiddraw();}Step2具体图形实现publicclassCircleimplementsShape{Overridepublicvoiddraw(){System.out.println(绘制圆形);}}publicclassSquareimplementsShape{Overridepublicvoiddraw(){System.out.println(绘制正方形);}}Step3稳定的绘制工具publicclassShapeDrawer{// 依赖抽象不依赖具体publicvoiddrawShape(Shapes){s.draw();}}扩展三角形完全不用改旧代码publicclassTriangleimplementsShape{Overridepublicvoiddraw(){System.out.println(绘制三角形);}}5. 开闭原则总结核心扩展不改旧关键面向抽象/接口编程目的系统稳定、易扩展、低风险二、里氏替换原则 LSP1. 核心思想子类可以完全替换父类程序行为不变。父类能用的地方子类换上去照样跑逻辑不崩、结果不错。这是继承是否合理的唯一标准。2. 核心理解继承不是为了复用代码继承是为了行为统一子类必须是父类的真正子类型3. 经典反例正方形≠长方形// 父类长方形classRectangle{intwidth;intheight;voidsetWidth(intw){widthw;}voidsetHeight(inth){heighth;}}// 子类正方形错误继承classSquareextendsRectangle{voidsetWidth(intw){widthheightw;}voidsetHeight(inth){widthheighth;}}测试逻辑会崩voidresize(Rectangler){r.setWidth(20);// 预期高度不变}问题子类破坏父类行为约定无法替换父类违反里氏替换4. 正例遵守LSPStep1抽象父类publicabstractclassShape{publicabstractintgetArea();}Step2各自实现publicclassRectangleextendsShape{privateintw,h;publicRectangle(intw,inth){this.ww;this.hh;}OverridepublicintgetArea(){returnw*h;}}publicclassSquareextendsShape{privateintside;publicSquare(intside){this.sideside;}OverridepublicintgetArea(){returnside*side;}}Step3任意替换Shapes1newRectangle(10,20);Shapes2newSquare(10);行为完全一致安全替换。5. 里氏替换总结核心子类能替父类行为不跑偏关键继承看行为不看代码复用目的保证多态安全、系统稳定三、依赖倒置原则 DIP1. 核心思想高层不依赖低层二者都依赖抽象。抽象不依赖细节细节依赖抽象。大白话别直接new具体类依赖接口/抽象类实现可以随便换高层不动2. 为什么重要解耦解耦解耦换组件不用改高层方便测试、方便扩展是Spring/IOC的核心思想3. 反例高层依赖具体实现// 低层MySQL实现publicclassMySQLDao{publicvoidqueryUser(){System.out.println(MySQL查询用户);}}// 高层直接new死强耦合publicclassUserService{privateMySQLDaomySQLDaonewMySQLDao();publicvoidgetUserInfo(){mySQLDao.queryUser();}}问题换Oracle必须改UserService紧耦合、难扩展、难测试4. 正例依赖抽象Step1抽象接口publicinterfaceUserDao{voidqueryUser();}Step2具体实现publicclassMySQLDaoimplementsUserDao{OverridepublicvoidqueryUser(){System.out.println(MySQL查询);}}publicclassOracleDaoimplementsUserDao{OverridepublicvoidqueryUser(){System.out.println(Oracle查询);}}Step3高层依赖抽象publicclassUserService{privateUserDaouserDao;// 注入构造/Setter都行publicUserService(UserDaodao){this.userDaodao;}publicvoidgetUserInfo(){userDao.queryUser();}}使用publicclassTest{publicstaticvoidmain(String[]args){// 随意切换高层代码完全不动UserServiceservicenewUserService(newMySQLDao());service.getUserInfo();servicenewUserService(newOracleDao());service.getUserInfo();}}5. 依赖倒置总结核心依赖抽象不依赖具体关键面向接口编程、依赖注入目的极致解耦、高灵活、易扩展四、三大原则终极总结原则英文一句话口诀核心解决开闭原则OCP能扩不改旧扩展风险、稳定性里氏替换LSP子类能替父类继承安全、多态正确依赖倒置DIP依赖抽象不绑死解耦、扩展、替换一句话串起来用里氏替换保证继承正确用依赖倒置实现解耦最终达到开闭原则——扩展不改、系统稳定。五、课堂小测面试常考新增支付方式直接修改支付工具类 → 违反开闭原则子类替换父类后逻辑异常 → 违反里氏替换原则Service直接new Dao换库要改代码 → 违反依赖倒置原则六、总结这三大原则是设计模式的基础也是高级工程师必备素养。简单工厂 → 工厂方法就是为了遵守开闭Spring IOC/AOP核心就是依赖倒置合理继承必须遵守里氏替换建议收藏每次写代码前对照一遍代码质量直接上一个档次。

更多文章