网站建设第三方平台,移动开发主要学什么,网站信息维护方案,网站的话术目录
一、单一职责原则#xff08;Single Responsibility Principle, SRP#xff09;
二、开放封闭原则#xff08;Open-Closed Principle, OCP#xff09;
三、依赖倒置原则#xff08;Dependency Inversion Principle, DIP#xff09;
四、里氏替换原则Single Responsibility Principle, SRP
二、开放封闭原则Open-Closed Principle, OCP
三、依赖倒置原则Dependency Inversion Principle, DIP
四、里氏替换原则Liskov Substitution Principle, LSP
五、接口隔离原则Interface Segregation Principle, ISP
六、合成复用原则Composite Reuse Principle, CRP
七、迪米特法则Demeter Principle, DP 设计模式的七大原则是软件设计和开发中的重要指导原则它们帮助开发者创建可扩展、可维护和灵活的软件系统。这些原则包括
单一职责原则Single Responsibility Principle, SRP一个类应该只有一个引起变化的原因。这意味着每个类应该有一个明确的职责并且仅负责完成一项功能这样可以使类更加模块化和可维护。开放封闭原则Open-Closed Principle, OCP软件实体如类、模块或函数应该对扩展开放对修改关闭。这意味着当软件需要适应新的环境或需求时应该通过添加新的代码来扩展系统的行为而不是修改现有的代码。依赖倒置原则Dependency Inversion Principle, DIP高层模块不应该依赖于低层模块它们都应该依赖于抽象。抽象不应该依赖于细节细节应该依赖于抽象。这意味着代码应该依赖于接口或抽象类而不是具体的实现类。里氏替换原则Liskov Substitution Principle, LSP子类型必须能够替换其基类型而不会产生任何问题。这确保了继承关系的正确使用子类应该能够保持与父类相同的接口和行为从而保持系统的稳定性和可维护性。接口隔离原则Interface Segregation Principle, ISP客户端不应该依赖于它不需要的接口。这意味着接口应该被细分为更小的、更具体的接口这样客户端只需要知道和使用它感兴趣的方法。合成复用原则Composite Reuse Principle, CRP优先使用对象组合而不是继承来达到复用的目的。这意味着在面向对象设计中应该优先考虑通过组合或聚合关系来复用已有的设计和实现而不是通过继承。迪米特法则Demeter Principle, DP一个对象应当仅与它的朋友friendly objects说话。这有助于减少对象之间的耦合提高软件的可维护性和可读性。
遵循这些原则可以帮助开发人员创建更加灵活、可维护和可扩展的软件系统。
一、单一职责原则Single Responsibility Principle, SRP 定义一个类应该只有一个引起它变化的原因。
一个类 / 接口 / 方法只负责一项职责
优点降低类的负责度、提高类的可读性提高系统的可维护性、降低变更的风险。
public interface UserService {void updateUser(User user,int opt);
}
传入修改类型用户名去修改用户信息。但这里却违背了单一职责原则
改造方法
public interface UserService {void changeName(String name);void changePwd(String pwd);
}
这种更符合我们单一职责原则。
但是我们开发的时候可能会有些迷茫什么时候去划分什么时候放到一起那这个时候就应该去重新审视代码哪些是需要合并到一起哪些是要应用。
这里的原则既是最简单的原则也是最难的原则难的时候可能我们不是特别好区分。
二、开放封闭原则Open-Closed Principle, OCP 定义一个软件实体例如类、模块、函数应该对扩展是开放的对修改是关闭的。 实现用抽象构建框架用实现扩展细节。 优点提高软件系统的可复用性及可维护性。 用例
书籍实体
public interface IBook {/*** 编号* return*/Integer getId();/*** 名称* return*/String getName();/*** 价格* return*/Double getPrice();
}
书籍接口
public class BookImpl implements IBook {private Integer id;private String name;private Double price;public BookImpl(Integer id, String name, Double price) {this.id id;this.name name;this.price price;}Overridepublic Integer getId() {return id;}Overridepublic String getName() {return name;}Overridepublic Double getPrice() {return price;}}
测试用例
public class Test {public static void main(String[] args) {DiscountBookImpl book new DiscountBookImpl(1,java, 100.0);System.out.println(Book Id: book.getId() , Title: book.getTitle() , Price: book.getPrice());}
}
假设我们来了业务需求书籍打折我们在原来的书籍接口上这样修改
public class BookImpl implements IBook {private Integer id;private String name;private Double price;public BookImpl(Integer id, String name, Double price) {this.id id;this.name name;this.price price;}Overridepublic Integer getId() {return id;}Overridepublic String getName() {return name;}Overridepublic Double getPrice() {return this.price * 0.8;}}
这样本身就违背了我们这条原则正确的做法应该是
新建一个打折书籍接口
public class DiscountBookImpl extends BookImpl{public DiscountBookImpl(Integer id, String name, Double price, Double discount) {super(id, name, price);this.discount discount;}Overridepublic Double getPrice() {return super.getPrice() * 0.8;}public Double getOriginalPrice() {return super.getPrice();}
}
三、依赖倒置原则Dependency Inversion Principle, DIP 定义程序要依赖于抽象接口不要依赖于具体实现。简单的说就是要求对抽象进行编程不要对实现进行编程。 面向过程的开发上层调用下层上层依赖于下层当下层剧烈变动时上层也要跟着变动这就会导致模块的复用性降低而大大提高了开发的成本。
面向对象的开发很好的解决了这个问题一般情况下抽象的变化概率很小让用户程序依赖于抽象实现的细节也依赖于抽象。即使实现细节不断变动只要抽象不变客户程序就不需要变化。
优点可以减少类间的耦合性提高系统的稳定性提高代码可读性和维护性可降低修改程序所造成的风险。
用例
学生实体
public class Student {public void studyJavaCourse() {System.out.println(学习Java课程);}public void studyPythonCourse() {System.out.println(学习Python课程);}
}学生学习课程
public class Test {public static void main(String[] args) {Student student new Student();student.studyJavaCourse();student.studyPythonCourse();}
}
降低耦合改造
新建课程接口
public interface ICourse {void study();
}
新建Java课程类
public class JavaCourse implements ICourse {Overridepublic void study(){System.out.println(JavaCourse study);}
}新建Python类
public class PythonCourse extends ICourse {Overridepublic void study(){System.out.println(PythonCourse study);}
}
改造学生实现类
public class Student {public void study(ICourse course){course.study();}
}
改造测试类
public class Test {public static void main(String[] args) {JavaCourse javaCourse new JavaCourse();Student student new Student();Student.study(javaCourse);}
}
改造之后依赖于上层、下层通过接口访问。
改造2【利用Spring构造器依赖注入原理】
Student改造
public class Student {ICourse course;public Student(ICourse course){this.course course;}public void study(){course.study();}
}
测试类改造
public class Test {public static void main(String[] args) {JavaCourse javaCourse new JavaCourse();Student student new Student(javaCourse);Student.study();}
}
改造3【利用Spring Set注入】
Student改造
public class Student {ICourse course;public void setCourse(ICourse course){this.course course;}public void study(){course.study();}
}
测试类改造
public class Test {public static void main(String[] args) {JavaCourse javaCourse new JavaCourse();Student student new Student();student.setCourse(javaCourse);Student.study();}
} 备注执行的过程是一样的 四、里氏替换原则Liskov Substitution Principle, LSP
定义派生类子类对象可以在程式中替代其基类超类对象。
因为继承带来的侵入性增加了耦合性也降低了代码灵活性父类修改代码子类也会受到影响此时就需要里氏替换原则。
子类必须实现父类的抽象方法但不得重写覆盖父类的非抽象已实现方法。【在java里面可以重写但是不建议】子类中可以增加自己特有的方法。当子类覆盖或实现父类的方法时方法的前置条件即方法的形参要比父类方法的输入参数更宽松。当子类的方法实现父类的抽象方法时方法的后置条件即方法的返回值要比父类更严格。
用例
父类
public class Parent {public void method(int i){System.out.println(Parent method);}
}
子类
public class Child extends Parent {Overridepublic void method(int i){System.out.println(Child method);}
}
单元测试
public class Test {public static void main(String[] args) {Parent p new Parent();p.method(10);}
}
执行结果 当改成子类时
public class Test {public static void main(String[] args) {Parent p new Child();p.method(10);}
} 用里氏替换原则进行调整。
父类
public abstract class Parent {public List method(ArrayList i){return null;}public abstract ArrayListString method(List i);public abstract void abstractMethod(int i);
}
子类
public class Child extends Parent {Overridepublic ArrayListString method(List i){System.out.println(Child method);return null;}Overridepublic void abstractMethod(int i) {}public void method2(int i){System.out.println(Child method2);}
}
优点
提高了代码的重用性子类拥有父类的方法和属性提高代码的可扩展性子类可形似于父类但异于父类保留自我的特性
缺点侵入性、不够灵活、高耦合
继承是侵入的只要继承就必须拥有父类的所有方法和属性在一定程度上约束了子类降低了代码的灵活性增加了耦合当父类的常量、变量或者方法被修改了需要考虑子类的修改所以一旦父类有了变动很可能会造成非常糟糕的结果要重构大量的代码。
五、接口隔离原则Interface Segregation Principle, ISP
定义用多个专门的接口不使用单一的总接口客户端不应该依赖他不需要的接口
一个类对应一个类的依赖应该建立在最小的接口上建立单一接口不要建立庞大臃肿的接口尽量细化接口接口中的方法尽量少
优点符合高内聚低耦合的设计思想从而使得类具有很好的可读性、可扩展性和可维护性
通俗点讲把几个大的接口分成小接口把接口细化。
动物接口
public interface IAnimal {void pref();void fly();void swim();
}狗实体
public class Dog implements Animal {Overridepublic void prey(){}Overridepublic void fly(){}Overridepublic void swim(){}
}
但是狗不会飞
鸟实体
public class Bird implements Animal{Overridepublic void prey(){}Overridepublic void fly(){}Overridepublic void swim(){}
}
鸟也不会游泳
这个时候我们就应该把接口隔离把它分开。 public class Bird implements IPreyable, IFlyable{Overridepublic void prey(){}Overridepublic void fly(){}
}
设计接口的时候呢过大过小都不好只有不断的思考才能去实现
六、合成复用原则Composite Reuse Principle, CRP
定义软件复用时要尽量先使用组合或者聚合等关联关系来实现其次才考虑使用继承关系来实现。
问题由来通常类的复用分为继承复用和合成复用两种继承复用虽然有简单和易实现的优点但它也存在以下缺点。
继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类父类对子类是透明的所以这种复用又称为“白箱”复用。子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化这不利于类的扩展与维护。它限制了复用的灵活性。从父类继承而来的实现是静态的在编译时已经定义所以在运行时不可能发生变化。
解决方案合成复用原则是通过将已有的对象纳入新对象中作为新对象的成员对象来实现的新对象可以调用已有对象的功能从而达到复用的效果。
继承关系
引擎类
public class Engine {//发动机功率String power;//发动机排量String displacement;
}
汽车类
public class Car extends Engine {//汽车型号String type;//汽车重量String weight;
}
使用合成类进行改造
public class Car{//汽车型号String type;//汽车重量String weight;Engine engine;
}
使用之前的类作为现在的一个属性
合成是拥有关系聚合是整体与部分的关系。
聚合班级学生班级是一个整体学生是一个部分一个班级里有很多班级这种关系叫聚合。而汽车汽车有很多构建他们有很多东西组成。聚合是实心的对象与实心的组合而合成是空心与实心的实现。两者非常像。要根据具体业务进行区分。
七、迪米特法则Demeter Principle, DP
定义一个对象对其他对象保持最少的了解。又叫最少知道原则
通俗点讲小明、小张都想知道彼此新入职公司对方的工资但是他们作为职业打工人心里都默念打工人基本素养社会上的事情少打听以免破坏员工和谐
强调只和朋友交流朋友出现在成员变量、方法的输入、输出参数中的类成为成员朋友类而出现在方法体内部的类不属于朋友类
优点降低类之间的耦合
1987年美国在一个项目组提出的概念。
用例
学生类
public class Student {}
班长类
public class Monitor {public void count(ListStudent students){System.out.println(学生数students.size());}
}
老师类
public class Teacher {public void commond(Monitor monitor){ListStudent students new ArrayList();for(int i0;i10;i){students.add(new Student());}monitor.count(students);}
}
测试类
public class Test {public static void main(String[] args) {Teacher teacher new Teacher();teacher.commond(new Monitor());}
} 改造老师只跟班长进行交流、不跟学生进行交流
班长类
public class Monitor {public void count(){ListStudent students new ArrayList();for(int i0;i10;i){students.add(new Student());}System.out.println(学生数students.size());}
}
老师类
public class Teacher {public void commond(Monitor monitor){monitor.count();}
}
单元测试类
public class Test {public static void main(String[] args) {Teacher teacher new Teacher();teacher.commond(new Monitor());}
}
明显职责变得更清晰了