开闭原则
开闭原则(Open-Closed Principle, OCP)是指一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。所谓的开闭,也正是对扩展和修改两个行为的一个原则。强调的是用抽象构建框架,用实现扩展细节。可以提高软件系统的可复用性及可维护性。开闭原则,是面向对象设计中最基础的设计原则。它指导我们如何建立稳定灵活的系统,例如:我们版本更新,我尽可能不修改源代码,但是可以增加新功能。
例如:计算商品价格接口实现类已经写好,这时需求有变做活动打折。
//接口
public interface TestCoreService {
Integer getPrice();
String name();
}
//实现类
public class TestCoreServiceImpl implements TestCoreService {
private String name;
private Integer price;
public TestCoreServiceImpl(Integer price) {
this.price = price;
}
@Override
public Integer getPrice() {
return this.price;
}
@Override
public String name() {
return this.name;
}
public void setPrice(Integer price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//继承实现类,对添加保持开放
public class TestExtendCoreServiceImpl extends TestCoreServiceImpl {
public TestExtendCoreServiceImpl(Integer price) {
super(price);
}
public Integer price() {
return (int) (super.getPrice() * 0.75);
}
//测试
public static void main(String[] args) {
TestExtendCoreServiceImpl te = new TestExtendCoreServiceImpl(100);
System.out.println(te.price());
}
}
总结:保证对添加开放,对修改关闭的思想。
依赖倒置原则
依赖倒置原则(Dependence Inversion Principle,DIP)是指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节;细节应该依赖抽象。通过依赖倒置,可以减少类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并能够降低修改程序所造成的风险。
例如:有一个培训机构培训篮球,足球,有一个小朋友想学篮球。
//创建一个学习机构
public interface TestJiGou {
void study();
}
//篮球培训
public class TestStudyLanQiuImpl implements TestJiGou {
@Override
public void study() {
System.out.println(“我要学篮球”);
}
}
//足球培训
public class TestStudyZuQiuImpl implements TestJiGou {
@Override
public void study() {
System.out.println(“我要学足球”);
}
}
//luce小朋友
public class Luce {
public void study(TestJiGou jigou) {
jigou.study();
}
//测试
public static void main(String[] args) {
Luce luce = new Luce();
luce.study(new TestStudyLanQiuImpl());
}
}
尽量保证上层的TestJiGou 接口不变化
(1)当我的机构添加培训科目时只要实现机构接口即可
(2)当有小朋友学习其他科目时只要传入相应学习类参数即可
总结:框架搭建是保证上层架构的稳定设计,尽量保证不改动。以抽象为基准比以细节为基准搭建起来的架构要稳定得多,因此在拿到需求之后,要面向接口编程,先顶层再细节来设计代码结构。
单一职责原则
单一职责(Simple Responsibility Pinciple,SRP)是指不要存在多于一个导致类变更的原因。假设我们有一个 Class 负责两个职责,一旦发生需求变更,修改其中一个职责的逻辑代码,有可能会导致另一个职责的功能发生故障。这样一来,这个 Class 存在两个导致类变更的原因。如何解决这个问题呢?我们就要给两个职责分别用两个 Class 来实现,进行解耦。后期需求变更维护互不影响。这样的设计,可以降低类的复杂度,提高类的可 读 性 , 提 高 系 统 的 可 维 护 性 , 降 低 变 更 引 起 的 风 险 。 总 体 来 说 就 是 一 个Class/Interface/Method 只负责一项职责。
例如:接口中的添加,修改方法分开写解耦、
//接口
public interface TestInter {
void add();
void update();
}
//实现类
public class TestImpl implements TestInter {
@Override
public void add() {
System.out.println("实现添加");
}
@Override
public void update() {
System.out.println("实现修改");
}
}
添加的接口通常可以和修改的接口写在一起的,但是单一原则是保证我增加添加逻辑的时候不要影响到修改方法,所以建议分开写,保证代码互不干扰。在编写代码的过程,尽可能地让接口和方法保持单一职责,对我们项目后期的维护是有很大帮助的。
总结:单一职责原则是保证接口方法解耦,维护时候互相不影响。
接口隔离原则
接口隔离原则(Interface Segregation Principle, ISP)是指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。这个原则指导我们在设计接口时应当注意一下几点:
1、一个类对一类的依赖应该建立在最小的接口之上。
2、建立单一接口,不要建立庞大臃肿的接口。
3、尽量细化接口,接口中的方法尽量少(不是越少越好,一定要适度)。
接口隔离原则符合我们常说的高内聚低耦合的设计思想,从而使得类具有很好的可读性、可扩展性和可维护性。我们在设计接口的时候,要多花时间去思考,要考虑业务模型,包括以后有可能发生变更的地方还要做一些预判。
例如:添加汽车,修改汽车,如果我有添加飞机的方法请不要写在这个接口中因为我需要接口分离,我在实现汽车的接口是不需要飞机的哦!!!!
//汽车接口
public interface TestInter {
void addQiChe();
void updateQiChe();
// void updateFeiJi();//在实现汽车的接口不需要他,接口分离他
}
//汽车实现类
public class TestImpl implements TestInter {
@Override
public void addQiChe() {
System.out.println(“添加汽车”);
}
@Override
public void updateQiChe() {
System.out.println(“修改汽车”);
}
}
总结:分离接口是尽量让实现类中每一个重写的函数有意义、
迪米特法则
迪米特原则(Law of Demeter LoD)是指一个对象应该对其他对象保持最少的了解,又叫最少知道原则(Least Knowledge Principle,LKP),尽量降低类与类之间的耦合。迪米特原则主要强调只和朋友交流,不和陌生人说话。出现在成员变量、方法的输入、输出参数中的类都可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类。
迪米特法则再测不举例子。
个人理解:迪米特法则,就是只做跟自己直接相关的工作,间接关联的不做。
如:
老板只关注项目质量,进度。
Java项目管理者应该注意项目周期、项目进度,而不去写真正的写代码。
开发人员,业务代码进度。
老板想知道项目进度,直接问项目管理者,而不是去问开发代码进度再去问项目管理者。这就是我说的只做直接事情不做间接事情、
里氏替换原则
里氏替换原则(Liskov Substitution Principle,LSP)是指如果对每一个类型为 T1 的对象 o1,都有类型为 T2 的对象 o2,使得以 T1 定义的所有程序 P 在所有的对象 o1 都替换成o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。定义看上去还是比较抽象,我们重新理解一下,可以理解为一个软件实体如果适用一个
父类的话,那一定是适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。
引申含义:子类可以扩展父类的功能,但不能改变父类原有的功能。
1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
2、子类中可以增加自己特有的方法。
3、当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类方法的输入参数更宽松。
4、当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或相等。
使用里氏替换原则有以下优点:
1、约束继承泛滥,开闭原则的一种体现。
2、加强程序的健壮性,同时变更时也可以做到非常好的兼容性,提高程序的维护性、扩展性。降低需求变更时引入的风险。
合成复用原则
合成复用原则(Composite/Aggregate Reuse Principle,CARP)是指尽量使用对象组合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的。可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。继承我们叫做白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合也称之为黑箱复用,对类以外的对象是无法获取到实现细节的。要根据具体的业务场景来做代码设计,其实也都需要遵循 OOP 模型。
例如:数据库连接
//连接抽象类
public abstract class DBConnection {
public abstract String getConnection();
}
//连接mysql
public class MySQLConnection extends DBConnection {
@Override
public String getConnection() {
return “MySQL 数据库连接”;
}
}
//调用连接数据库的抽象类(oop面向对象)
public class ProductDao{
//创建对象
private DBConnection dbConnection;
public void setDbConnection(DBConnection dbConnection) {
this.dbConnection = dbConnection;
}
public void addProduct(){
//调用对象方法
String conn = dbConnection.getConnection();
System.out.println(“使用”+conn+“增加产品”);
}
}
连接数据库是典型的合成复用原则,面向对象编程的经典操作。
没有绝对优美的代码,只有更加适合的场景。平衡取舍,让我们设计出更加优雅的代码结构。
(请大家提出自己的看法,互相促进,共同进步)
来源:CSDN
作者:扬帆起航@JAVA
链接:https://blog.csdn.net/qq_38208622/article/details/103495756