咱们首先了解一个单词
solid
这个单词和咱们今天要讲述的七大原则有什么关系?
咱们首先要了解七大原则都有什么?
- 单一职责原则 (Single Responsibility Principle)
- 开放-关闭原则 (Open-Closed Principle)
- 里氏替换原则 (Liskov Substitution Principle)
- 接口隔离原则 (Interface Segregation Principle)
- 依赖倒转原则 (Dependence Inversion Principle)
- 迪米特法则(Law Of Demeter)
- 组合/聚合复用原则 (Composite/Aggregate Reuse Principle)
咱们来进行详细的讲解。
1、单一职责原则
定义:
单一职责原则(Single Responsibility Principle,SRP)又称单一功能原则,由罗伯特·C.马丁(Robert C. Martin)于《敏捷软件开发:原则、模式和实践》一书中提出的。这里的职责是指类变化的原因,单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分(There should never be more than one reason for a class to change)。
优点:
单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高其内聚性。如果遵循单一职责原则将有以下优点。
1、降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多。
2、提高类的可读性。复杂性降低,自然其可读性会提高。
3、提高系统的可维护性。可读性提高,那自然更容易维护了。
4、变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响。
类层面:
错误示范:
public class SingleResponsibility1 { public static void main(String[] args) { Vehicle vehicle = new Vehicle(); vehicle.run("汽车"); vehicle.run("飞机"); vehicle.run("轮船"); } } class Vehicle { public void run(String vehicle) { System.out.println(vehicle + " 在公路运行..."); } }
汽车 在公路运行... 飞机 在公路运行... 轮船 在公路运行...
正确示范:
public class SingleResponsibility2 { public static void main(String[] args) { RoadVehicle roadVehicle = new RoadVehicle(); roadVehicle.run("汽车"); AirVehicle airVehicle = new AirVehicle(); airVehicle.run("飞机"); WaterVehicle waterVehicle = new WaterVehicle(); waterVehicle.run("轮船"); } } class RoadVehicle { public void run(String vehicle) { System.out.println(vehicle + " 在公路运行..."); } } class AirVehicle { public void run(String vehicle) { System.out.println(vehicle + " 在天空运行..."); } } class WaterVehicle { public void run(String vehicle) { System.out.println(vehicle + " 在水上运行..."); } }
汽车 在公路运行... 飞机 在天空运行... 轮船 在水上运行...
接口层面:
我们假设一个场景, 大家一起做家务, 张三扫地, 李四买菜. 李四买完菜回来还得做饭. 这个逻辑怎么实现呢?
错误示范:
/** * 做家务 */ public interface HouseWork { // 扫地 void sweepFloor(); // 购物 void shopping(); } public class Zhangsan implements HouseWork{ @Override public void sweepFloor() { // 扫地 } @Override public void shopping() { } } public class Lisi implements HouseWork{ @Override public void sweepFloor() { } @Override public void shopping() { // 购物 } }
首先定义了一个做家务的接口, 定义两个方法扫地和买菜. 张三扫地, 就实现扫地接口. 李四买菜, 就实现买菜接口. 然后李四买完菜回来还要做饭, 于是就要在接口类中增加一个方法cooking. 张三和李四都重写这个方法, 但只有李四有具体实现.
这样设计本身就是不合理的. 首先: 张三只扫地, 但是他需要重写买菜方法, 李四不需要扫地, 但是李四也要重写扫地方法. 第二: 这也不符合开闭原则. 增加一种类型做饭, 要修改3个类. 这样当逻辑很复杂的时候, 很容易引起意外错误.
上面这种设计不符合单一职责原则, 修改一个地方, 影响了其他不需要修改的地方.
正确示范:
/** * 做家务 */ public interface Hoursework { } public interface Shopping extends Hoursework{ // 购物 void shopping(); } public interface SweepFloor extends Hoursework{ // 扫地 void sweepFlooring(); } public class Zhangsan implements SweepFloor{ @Override public void sweepFlooring() { // 张三扫地 } } public class Lisi implements Shopping{ @Override public void shopping() { // 李四购物 } }
上面做家务不是定义成一个接口, 而是将扫地和做家务分开了. 张三扫地, 那么张三就实现扫地的接口. 李四购物, 李四就实现购物的接口. 后面李四要增加一个功能做饭. 那么就新增一个做饭接口, 这次只需要李四实现做饭接口就可以了.
public interface Cooking extends Hoursework{ void cooking(); } public class Lisi implements Shopping, Cooking{ @Override public void shopping() { // 李四购物 } @Override public void cooking() { // 李四做饭 } }
如上, 我们看到张三没有实现多余的接口, 李四也没有. 而且当新增功能的时候, 只影响了李四, 并没有影响张三. 这就是符合单一职责原则. 一个类只做一件事. 并且他的修改不会带来其他的变化.
2、开放-关闭原则 (Open-Closed Principle)
定义
开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。其他的设计原则,很多时候是为实现这一目标服务的.
具体描述
● 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
● 对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对已有代码进行任何修改
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。
示例
错误实例:
public class OpenClosed1 { public static void main(String[] args) { GraphicEditor graphicEditor = new GraphicEditor(); graphicEditor.drawShape(new Rectangle()); graphicEditor.drawShape(new Circle()); graphicEditor.drawShape(new Triangle());//+新增绘制三角形 } }
//这是一个用于绘图的类 class GraphicEditor { //接收 Shape 对象,然后根据 type 来绘制不同的图形 public void drawShape(Shape s) { if (s.m_type == 1) drawRectangle(s); else if (s.m_type == 2) drawCircle(s); else if (s.m_type == 3)//+新增绘制三角形 drawTriangle(s); } //绘制矩形 public void drawRectangle(Shape r) { System.out.println("绘制矩形"); } //绘制圆形 public void drawCircle(Shape r) { System.out.println("绘制圆形"); } //+新增绘制三角形 public void drawTriangle(Shape r) { System.out.println("绘制三角形"); } } class Shape { int m_type; } //以前就写好的 class Rectangle extends Shape { Rectangle() { super.m_type = 1; } } //以前就写好的 class Circle extends Shape { Circle() { super.m_type = 2; } } //+新增绘制三角形 class Triangle extends Shape { Triangle() { super.m_type = 3; } }
绘制矩形 绘制圆形 绘制三角形