设计模式七大原则解读(二)

简介: 设计模式七大原则解读(二)

依赖倒转原则

基本介绍

依赖倒转原则(Dependence Inversion Principle)是指:
1) 高层模块不应该依赖低层模块,二者都应该依赖其抽象
2) 抽象不应该依赖细节,细节应该依赖抽象
3) 依赖倒转(倒置)的中心思想是面向接口编程
4) 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在 java 中,抽象指的是接口或抽象类,细节就是具体的实现类

5) 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成

应用实例

请编程完成 Person 接收消息的功能

1) 实现方案 1 + 分析说明

1. public class DependecyInversion {
2. public static void main(String[] args) {
3. 
4.     }
5. }
6. class Email {
7. public String getInfo() {
8. return "电子邮件信息: hello,world";
9.     }
10. }
11. 
12. class Person {
13. public void receive(Email email ) {
14.         System.out.println(email.getInfo());
15.     }
16. }

方式 1 分析
1. 简单,比较容易想到
2. 如果我们获取的对象是 微信,短信等等,则新增类,同时 Perons 也要增加相应的接收方法
3. 解决思路:引入一个抽象的接口 IReceiver, 表示接收者, 这样 Person 类与接口 IReceiver 发生依赖,因为 Email, WeiXin 等等属于接收的范围,他们各自实现 IReceiver 接口就 ok, 这样我们就符号依赖倒转原则

2) 实现方案 2(依赖倒转) + 分析说明

1. public class DependecyInversion2 {
2. public static void main(String[] args) {
3. //客户端无需改变
4. Person person = new Person();
5.         person.receive(new Email2());
6.         person.receive(new WeiXin2());
7.     }
8. }
9. //定义接口
10. interface IReceiver {
11. public String getInfo();
12. }
13. class Email2 implements IReceiver {
14. public String getInfo() {
15. return "电子邮件信息: hello,world";
16.     }
17. }
18. //增加微信
19. class WeiXin2 implements IReceiver {
20. public String getInfo() {
21. return "微信信息: hello,ok";
22.     }
23. }
24. //方式 2
25. class Person2 {
26. //这里我们是对接口的依赖
27. public void receive(IReceiver receiver ) {
28.         System.out.println(receiver.getInfo());
29.     }
30. }

3)依赖关系传递的三种方式和应用案例

1) 接口传递==》应用案例代码

1. interface IOpenAndClose {
2. public void open(ITV tv); //抽象方法,接收接口
3. }
4. 
5. interface ITV { //ITV 接口
6. public void play();
7. }
8. 
9. class ChangHong implements ITV {
10. 
11. @Override
12. public void play() {
13. // TODO Auto-generated method stub
14.         System.out.println("长虹电视机,打开");
15.     }
16. 
17. }
18. // 实现接口
19. class OpenAndClose implements IOpenAndClose {
20. public void open(ITV tv) {
21.         tv.play();
22.     }
23. }

2) 构造方法传递==》应用案例代码

1. // 方式 2: 通过构造方法依赖传递
2. interface IOpenAndClose {
3. public void open(); //抽象方法
4. }
5. 
6. interface ITV { //ITV 接口
7. public void play();
8. }
9. 
10. class OpenAndClose implements IOpenAndClose {
11. public ITV tv; //成员
12. 
13. public OpenAndClose(ITV tv) { //构造器
14. this.tv = tv;
15.     }
16. 
17. public void open() {
18. this.tv.play();
19.     }
20. }

3) setter 方式传递==》应用案例代码

1. // 方式 3 , 通过 setter 方法传递
2. interface IOpenAndClose {
3. public void open(); // 抽象方法
4. 
5. public void setTv(ITV tv);
6. }
7. 
8. interface ITV { // ITV 接口
9. public void play();
10. }
11. 
12. class OpenAndClose implements IOpenAndClose {
13. private ITV tv;
14. 
15. public void setTv(ITV tv) {
16. this.tv = tv;
17.     }
18. 
19. public void open() {
20. this.tv.play();
21.     }
22. }
23. 
24. class ChangHong implements ITV {
25. @Override
26. public void play() {
27. // TODO Auto-generated method stub
28.         System.out.println("长虹电视机,打开");
29.     }
30. }

依赖倒转原则的注意事项和细节

1) 低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好.

2) 变量的声明类型尽量是抽象类或接口, 这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化

3) 继承时遵循里氏替换原则

里氏替换原则

OO 中的继承性的思考和说明

1) 继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。
2) 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障
3) 问题提出:在编程中,如何正确的使用继承? => 里氏替换原则

基本介绍

1) 里氏替换原则(Liskov Substitution Principle)在 1988 年,由麻省理工学院的以为姓里的女士提出的。
2) 如果对每个类型为 T1 的对象 o1,都有类型为 T2 的对象 o2,使得以 T1 定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。换句话说,所有引用基类的地方必须能透明地使用其子类的对象。
3) 在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法
4) 里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖 来解决问题。

一个程序引出的问题和思考

该看个程序, 思考下问题和解决思路

1. public class Liskov {
2. public static void main(String[] args) {
3. // TODO Auto-generated method stub
4. A a = new A();
5.         System.out.println("11-3=" + a.func1(11, 3));
6.         System.out.println("1-8=" + a.func1(1, 8));
7.         System.out.println("-----------------------");
8. B b = new B();
9.         System.out.println("11-3=" + b.func1(11, 3));//这里本意是求出 11-3
10.         System.out.println("1-8=" + b.func1(1, 8));// 1-8
11.         System.out.println("11+3+9=" + b.func2(11, 3));
12.     }
13. }
14. 
15. // A 类
16. class A {
17. // 返回两个数的差
18. public int func1(int num1, int num2) {
19. return num1 - num2;
20.     }
21. }
22. 
23. // B 类继承了 A
24. // 增加了一个新功能:完成两个数相加,然后和 9 求和
25. class B extends A {
26. //这里,重写了 A 类的方法, 可能是无意识
27. public int func1(int a, int b) {
28. return a + b;
29.     }
30. 
31. public int func2(int a, int b) {
32. return func1(a, b) + 9;
33.     }
34. }

我们发现原来运行正常的相减功能发生了错误。原因就是类 B 无意中重写了父类的方法,造成原有功能出现错误。在实际编程中,我们常常会通过重写父类的方法完成新的功能,这样写起来虽然简单,但整个继承体系的复用性会比较差。特别是运行多态比较频繁的时候

相关文章
|
2天前
|
设计模式 前端开发 Java
设计模式之六大基本原则
设计模式之六大基本原则
20 0
|
6月前
|
设计模式 Java 程序员
|
7月前
|
设计模式 Java 测试技术
Java设计模式七大原则-接口隔离原则
Java设计模式七大原则-接口隔离原则
42 0
|
2天前
|
设计模式 算法 架构师
【搞懂设计模式】设计模式与面向对象原则
【搞懂设计模式】设计模式与面向对象原则
6 1
|
2天前
|
设计模式 前端开发 API
写出易维护的代码|React开发的设计模式及原则
本文对React社区里出现过的一些设计模式进行了介绍,并讲解了他们遵循的设计原则。
|
2天前
|
设计模式 数据可视化 关系型数据库
设计之美-揭秘设计模式、原则与UML的魔法
设计模式、设计原则和UML是软件工程设计中的核心要素。设计模式为常见问题提供经验证的解决方案,复用性高且提升开发效率。设计原则指导我们创建灵活、可维护和可扩展的系统,确保代码质量和长期可维护性。UML(统一建模语言)则是一种强大的可视化工具,用于描述、构建和文档化软件系统的结构和行为。它帮助开发者更清晰地理解系统架构和组件间关系。综合应用设计模式、设计原则和UML,能够显著提高软件开发的效率和质量,减少维护成本,为复杂系统的设计和实施提供有力支持。
37 0
设计之美-揭秘设计模式、原则与UML的魔法
|
2天前
|
设计模式 关系型数据库
设计模式的六大原则:理解设计模式的关键思想和应用
设计模式的六大原则:理解设计模式的关键思想和应用
18 2
|
2天前
|
设计模式
【设计模式】1、设计模式七大原则
【设计模式】1、设计模式七大原则
19 0
|
2天前
|
设计模式 存储 NoSQL
【设计模式】软件设计原则-单一职责原则
【1月更文挑战第12天】【设计模式】软件设计原则-单一职责原则
|
2天前
|
设计模式 关系型数据库
【设计模式】软件设置原则-开闭原则
【1月更文挑战第12天】【设计模式】软件设置原则-开闭原则