1.开闭原则

对扩展开放,对修改关闭。在程序需要进行扩展的时候,不能去修改原有的代码,要去实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。

下面是输入法设置皮肤的例子:

// 抽象皮肤接口
public interface Skin {// 显示的方法void display();
}
// 默认皮肤类
public class DefaultSkin implements Skin {@Overridepublic void display() {System.out.println("默认皮肤");}
}
// 下班了皮肤
public class OffWorkSkin implements Skin{@Overridepublic void display() {System.out.println("下班了皮肤");}
}
// 输入法类
@Data
public class Input {// 设置皮肤private Skin skin;public void display() {skin.display();}
}// 测试public static void main(String[] args){// 创建输入法对象Input input = new Input();// 创建皮肤对象Skin defaultSkin = new DefaultSkin();// 设置默认皮肤input.setSkin(defaultSkin);// 显示皮肤input.display(); // 默认皮肤// 换成下班了皮肤Skin offWorkSkin = new OffWorkSkin();input.setSkin(offWorkSkin);input.display();// 下班了皮肤}

2.单一职责原则

就一个类而言,应该仅有一个引起变化的原因。应该只有一个职责。

说白了就是,一个类或者一个方法就应该干一件事情。

下面是修改用户的例子:

public class UpdateUser {// 不符合单一职责原则public void updateUser(String type, String oldPassword, String newPassword, String oldUserName, String newUserName) {if ("修改密码".equals(type)) {System.out.println(oldPassword + "修改密码为:" + newPassword);} else if ("修改账号".equals(type)) {System.out.println(oldUserName + "修改账号" + newUserName);}}// 符合单一职责原则public void updatePassword(String oldPassword, String newPassword) {System.out.println(oldPassword + "修改密码为:" + newPassword);}public void updateUserName(String oldUserName, String newUserName) {System.out.println(oldUserName + "修改账号" + newUserName);}
}

可以看到上者是根据操作类型进行区分, 不同类型执行不同的逻辑,把修改账号和修改密码这两件事耦合在一起了,如果客户端在操作的时候传错了类型, 那么就会发生错误;

下者则把修改账号和修改密码逻辑分开,各自执行各自的职责,互不干扰,功能清晰明了,符合单一职责原则。

3.依赖倒置原则

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。简单来说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

下面是一个组装电脑的例子(简单举例电脑只保留CPU吧,嘻嘻嘻):

// Intel处理器类
public class IntelCpu {public void getCpu() {System.out.println("使用Intel处理器");}
}
// 电脑
@Data
public class Computer {private IntelCpu intelCpu; // CPUpublic void run() {intelCpu.getCpu();}
}// 测试public static void main(String[] args){// 创建电脑对象Computer computer = new Computer();// 设置CPUcomputer.setIntelCpu(new IntelCpu());computer.run(); // 使用Intel处理器}

可以看到上面的组装的电脑只能使用Intel的CPU,假如我想换成AMD的CPU不行。这就是违反了依赖倒置原则。修改后的代码如下:

// CPU类
public interface Cpu {void getCpu();
}
// Intel处理器类
public class IntelCpu implements Cpu {@Overridepublic void getCpu() {System.out.println("使用Intel处理器");}
}
// Amd处理器类
public class AmdCpu implements Cpu {@Overridepublic void getCpu() {System.out.println("使用Amd处理器");}
}
// 电脑
@Data
public class Computer {private Cpu cpu;public void run() {cpu.getCpu();}
}// 测试public static void main(String[] args){// 创建电脑对象Computer computer = new Computer();// 设置CPU为Intel处理器computer.setCpu(new IntelCpu());computer.run(); // 使用Intel处理器// 设置CPU为Amd处理器computer.setCpu(new AmdCpu());computer.run(); // 使用Amd处理器}

此时,当用户需要更换CPU时,只需要创建实现类去实现CPU接口而不需要修改原本的接口代码,这就符合了开闭原则。

4.接口隔离原则

客户端不应该被迫依赖于它不使用的方法;一个类对另一个类的依赖应该建立在最小的接口上。

下面用一个安全门的例子:

现在有A品牌的安全门具有防火防盗功能,于是把防火防盗的功能提取出来一个接口,即:

// 安全门接口
public interface Door {//防火void fireproof();//防水void waterproof();
}
// 安全门接口
public interface Door {//防火void fireproof();//防水void waterproof();
}

那么假如我们现在又有一个B品牌的安全门,只有防水功能的呢?那么显然是不能直接实现安全门的接口的,那么应该如何改进呢?改进如下:

// 防火功能
public interface FireProof {void fireProof();
}
// 防火功能
public interface FireProof {void fireProof();
}
// A类门,具有防火防水功能
public class ADoor implements WaterProof, FireProof {@Overridepublic void fireProof() {System.out.println("A品牌安全门防火功能");}@Overridepublic void waterProof() {System.out.println("A品牌安全门防水功能");}
}// B类安全门
public class BDoor implements WaterProof {@Overridepublic void waterProof() {System.out.println("B品牌安全门防水功能");}
}

这样改进以后可以看到,当不同的品牌的安全门具有不同的功能的时,有什么功能就实现什么功能的接口,假如以后还有一个C品牌类的安全门具有防火防水防盗的功能,那么可以加一个防盗的接口,然后C类门去实现防火防水防盗的接口即可。这就是接口隔离原则。

5.迪米特法则

迪米特法则又叫最少知识原则。如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。

当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。

下面是一个明星,粉丝,经纪公司的例子:

// 明星类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Star {private String name;
}
// 粉丝类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Fans {private String name;
}
// 经纪公司类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Company {private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Agent {private Star star;private Fans fans;private Company company;//和粉丝见面的方法public void meeting(){System.out.println(star.getName() + "和粉丝"+fans.getName() + "见面");}//和媒体公司洽谈的方法public void business(){System.out.println(star.getName() + "和" + company.getName() + "洽谈");}
}// 测试public static void main(String[] args) {//创建明星对象Star star = new Star("严晓波");//创建粉丝对象Fans fans = new Fans("彭晓锋");//创建公司对象Company company = new Company("杨永信电疗娱乐有限公司");//创建经纪人对象Agent agent = new Agent(star, fans, company);agent.meeting();// 严晓波和粉丝彭晓锋见面agent.business();// 严晓波和杨永信电疗娱乐有限公司洽谈}

这里明星的日常事务有经纪人负责处理,比如和粉丝见面,和媒体公司洽谈,这里明星的朋友是经纪人,而和粉丝和公司是陌生人,所以适合使用迪米特法则。本例子可知迪米特法则主要是为了降低明星与粉丝和公司之间的耦合度。

6.里氏替换原则

任何基类可以出现的地方,子类一定可以出现。子类可以扩展父类的功能,但不能改变父类原有的能。换句话说,子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

下面正方形不是长方形的例子:

// 长方形
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Rectangle {private Double length;private Double width;
}
// 正方形类(错误继承长方形)
public class Square extends Rectangle {@Overridepublic void setLength(Double length) {super.setLength(length);super.setWidth(length);}public void setWidth(Double width) {super.setLength(width);super.setWidth(width);}
}// 测试类
public class Test {public static void main(String[] args){// 创建长方形对象Rectangle rectangle = new Rectangle(15.0, 10.0);// 扩宽resize(rectangle);// 15.0// 16.0print(rectangle);System.out.println("====================");Square square = new Square();square.setLength(10.0);// 扩宽resize(square);// 死循环 直到oomprint(square);}// 扩宽修正方法public static void resize(Rectangle rectangle) {while (rectangle.getWidth() <= rectangle.getLength()) {rectangle.setWidth(rectangle.getWidth() + 1);}}// 打印长宽public static void print(Rectangle rectangle) {System.out.println(rectangle.getLength());System.out.println(rectangle.getWidth());}
}

可以从运行上面的代码看到,当我们调用resize()方法时候,普通长方形可以正常运行;但是当调用resize()方法的对象是正方形时,会死循环,这是因为正方形的长宽相等,永远都不会满足扩宽的条件。所以可以得出结论:在resize()方法中,长方形的参数是不能被正方形的参数所替代的,如果进行了替换就得不到预期的效果,所以Square和Rectangle类之间的继承关系违反了里氏代换原则,它们之间的继承关系不成立。修改后的代码如下:

// 四边形接口,长方形和正方形同属于四边形
public interface Quadrilateral {Double getLength(); // 获取长Double getWidth(); // 获取宽
}
// 长方形
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Rectangle implements Quadrilateral {private Double length;private Double width;
}
@Data
public class Square implements Quadrilateral {private Double side;@Overridepublic Double getLength() {return side;}@Overridepublic Double getWidth() {return side;}
}
// 测试类
public class Test {public static void main(String[] args){// 创建长方形对象Rectangle rectangle = new Rectangle(15.0, 10.0);// 扩宽resize(rectangle);// 15.0// 16.0print(rectangle);}// 扩宽修正方法public static void resize(Rectangle rectangle) {while (rectangle.getWidth() <= rectangle.getLength()) {rectangle.setWidth(rectangle.getWidth() + 1);}}// 打印长宽public static void print(Rectangle rectangle) {System.out.println(rectangle.getLength());System.out.println(rectangle.getWidth());}
}

这样Square类的对象就不能使用resize()方法。

7.合成复用原则

合成复用原则是指:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

通常类的复用分为继承复用和合成复用两种。

继承复用虽然有简单和易实现的优点,但它也有以下缺点:

  • 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称“白箱”复用。
  • 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展和维护。
  • 它限制了复用的灵活性。从父类继承而来的实现时静态的,在编译时已经定义,所以运行时不可能发生变化。

采用组合或聚合复用,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:

  • 它维持了类的封装性。因为成员对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
  • 对象间的耦合度低。可以在类的成员位置声明抽象。
  • 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的对象。

下面是汽车种类的例子:

继承复用

合成复用

Java中的七种设计原则相关推荐

  1. 面向对象的七种设计原则

    下面的截图:主要讲述了七种设计原则定名称,定义以及使用的频率.  原则一:(SRP:Single responsibility principle)单一职责原则又称单一功能原则 核心:解耦和增强内聚 ...

  2. 下雨天,留客天,天不留,我留七种设计原则!

    注:1,2,3,4,5显示的重要等级 常用的面向对象设计原则包括7个,这些原则并不是孤立存在的,它们相互依赖,相互补充. 一.开闭原则 1.          开闭原则定义 :一个软件实体应当对扩展开 ...

  3. 七种设计原则(二)单一职责原则

    2019独角兽企业重金招聘Python工程师标准>>> 1.定义 单一职责原则概念::规定一个类应该只有一个发生变化的原因. There should never be more t ...

  4. 程序设计中的几种设计原则

    依赖倒置原则(DIP) 高层模块(稳定)不应该依赖于底层模块(变换),二者都应该依赖于抽象(稳定) 抽象(稳定)不应该依赖于实现细节(变化), 实现细节应该依赖于抽象(稳定) 开闭原则 对扩展开放,对 ...

  5. 【设计模式】叩心自问:什么是设计模式? 设计模式的目的是什么?设计模式依据哪些(七种)原则设计的?设计模式有哪些?分类?

    aas 叩心自问 1 :设计模式的目的是什么? 叩心自问 2 :什么是设计模式? 叩心自问 3:设计模式依据哪些(七种)原则设计的? 3.1.单一职责原则 3.2.接口隔离原则 3.3.依赖倒转原则 ...

  6. Java 设计模式总结及六大设计原则

    设计模式总结 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式. ...

  7. 面向对象的三个基本特征 和 五种设计原则

    面向对象的三个基本特征 和 五种设计原则 来源: http://blog.csdn.net/cancan8538/article/details/8057095 一.三个基本特征 面向对象的三个基本特 ...

  8. 安全体系结构与七个设计原则

    安全体系结构的七个设计原则. FLASK体系结构的主要特点. FLASK体系结构中客体服务器OM和安全服务器的基本组成和作用. LSM框架的特点,及其对内核的主要修改 第一章安全体系结构的七个设计原则 ...

  9. java设计模式总结之六大设计原则(有图有例子)

    转载:https://www.cnblogs.com/jpfss/p/9765239.html 下面来总结下自己所学习的设计模式,首先我们看下各个模式之间的关系图,下面这张图是网上比较典型的一个类图关 ...

最新文章

  1. 解决“SSL handshake failed“问题
  2. 迎接奥运会 里约把机场的IT建设翻新了下
  3. python读文件写文件-python 文件读写操作
  4. 技术干货 | 视频最佳体验之自适应调节系统
  5. 开放下载!《一站式大数据开发治理DataWorks使用宝典》
  6. 轻松搞定对容器实例日志设置定期清理和回卷
  7. SAP Spartacus 3.0 加载homepage的逻辑
  8. spring容器注入一个接口的两个实现类
  9. 网络协议分析 | 传输层 :史上最全UDP、TCP协议详解,一篇通~
  10. 进程的创建-Process⼦类
  11. 小区移动基站安全吗?会杀人于无形吗?
  12. 《设计模式详解》手写简单的 Spring 框架
  13. DIV+CSS的命名规则有利于SEO
  14. 20130331java语言基础学习笔记-语句_breakcontinue
  15. python怎么播放音乐_Python实现在线音乐播放器
  16. matlab卡住了 打不开,win7系统matlab打不开无法运行的解决方法
  17. 百度Echarts设置markPoint展示样式
  18. 高端大气通用企业介绍PPT模板-优页文档
  19. ftp服务器与共享文件对比,ftp服务器与共享的区别
  20. 少儿编程会培养什么能力

热门文章

  1. ConvE,知识图谱嵌入(KGE)论文复现(Ubuntu 20.04)
  2. 放款2500亿仅占1%,度小满要做消费金融拉动内需的新动力?
  3. jsp mysql问卷调查_课内资源 - 基于JSP的在线调查问卷系统
  4. 【vue,SpringBoot,Mybatis】 关于多条件搜索表单
  5. java的SSPanel类_SpringBoot中遇到的一些问题
  6. jetbrains intellij idea从2021.2.3版本开始需要用户登录之后才能使用,2021.2.2版本以及之前的版本不用登录
  7. matlab中霍夫线检测函数,matlab 霍夫检测
  8. 大数据分析——暑期黑马《延禧攻略》到底有多火!
  9. base-64 字符数组的无效长度
  10. OKHttp源码解析 (复用连接池)