-设计模式七大基本原则分析+实战+总结(详细)
Posted 栗子~~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了-设计模式七大基本原则分析+实战+总结(详细)相关的知识,希望对你有一定的参考价值。
文章目录
- 前言
前言
如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!
万字大章-设计模式七大基本原则分析+实战+总结(详细)
01 什么是设计模式,为什么要学设计模式,它有什么好处?
在说原则之前,我们先说一下什么是设计模式,还有为什么要学。
设计模式概念:
是对软件设计中普遍存在的各种问题,所提出的解决方案,即当遇到问题时,可以重用这些方案来解决。
为什么要学习设计模式?
当你考虑到
1、在增加需求,现有程序如何变动成本是最低的。
2、如何保证新增的功能,对原有的功能不受影响。
这些问题时,就要学习设计思维了。
设计模式的好处:
1、设计模式可以让你的程序体现出更好的重用性、可读性、可扩展性,达到高内聚、低耦合的目的。
【内聚】: 主要描述模块的内容
【高内聚】:一个模块内的元素、关联性非常强。
【强耦合】: 发货系统 直接调用 订单系统
【低耦合】:模块之间耦合性比较低,A模块出错、不会影响B模块
如 发货系统 -》 消息中间件 -》 订单系统,这样的话耦合性就比较低,因为订单系统出现问题,不会影响发货系统
2、设计模式可以让你看源码有非常大的帮助。
3、设计模式也是合理重构的指南针(不改变原来功能的基础之上,调节程序代码)。
02 七大设计原则简单总结
原则 | 简单定义 |
---|---|
开闭原则 | 对扩展开放、对修改关闭(具有更好的扩展性) |
单一原则 | 一个类只负责一个功能领域的相应职责 |
依赖倒置原则 | 依赖于抽象,不能依赖于具体实现( 面向接口编程) |
里氏替换原则 | 所有引用基类的地方必须能透明的使用子类的对象 |
接口隔离原则 | 类之间的依赖关系应该建立在最小的接口上面 |
迪米特原则 | 一个软件实体应尽可能少于其他实体发生相互作用 |
组合/聚合复用原则 | 尽量使用组合/聚合,而不是通过继承达到复用的目的 |
03 开闭原则-分析实战
03::01 什么是开闭原则?
对扩展开放、对修改关闭(具有更好的扩展性)
扩展方式有哪些?
1、继承
2、组合
03::02 开闭原则分析
下面是一个违反开闭原则的一个实例。
/**
* @description: TODO 电脑的接口类 开闭原则: 对扩展开发、对修改关闭(具有更好的扩展性)
* @author yangzhenyu
* @date 2022/2/15 17:47
* @version 1.0
*/
interface Computer
void work();
//戴尔
class Dell implements Computer
@Override
public void work()
System.out.println("戴尔笔记本 ***** 好评");
//联想
class Lenovo implements Computer
@Override
public void work()
System.out.println("联想笔记本 ***** 好评");
interface ComputerFactory
//使用电脑类型
Computer toComputer();
class Factory
public Computer select(String code)
Computer computer = null;
if ("Dell".equals(code))
return new Dell();
else if ("Lenovo".equals(code))
return new Lenovo();
return computer;
分析: 当新增新的电脑属性时,会修改已有的代码,违反开闭原则。
我们来改造一下代码:
class YangZhenYu implements ComputerFactory
@Override
public Computer toComputer()
return new Dell();
class zhangSan implements ComputerFactory
@Override
public Computer toComputer()
return new Lenovo();
这样就可以了。
注:对于开闭原则来说,完全不修改代码是不可能的,只能尽可能的遵循开闭原则规范。
04 单一原则-分析实战
04::01 什么是单一原则?
简单定义:一个类只负责一个功能领域的相应职责。
大概意思是一个类只干一个业务,比方说:
一个类只负责下订单的业务,你不能将用户相关的业务放到这个类中。
即类的职责要单一,不能将太多的职责放在一个类中。
04::02 单一原则分析
下面是一个违反单一原则的实例,我们来看一下。
现有需求我们要改变其中一个方法的逻辑,将人类的行为改成动物的行为。
//人类
public interface Person
void work();
// 黄种人
class YellowPerson implements Person
@Override
public void work()
// 黑人
class BlackPerson implements Person
@Override
public void work()
分析:
当YellowPerson.work()方法的需求有变动,要从人类领域改成动物领域,
又因为Person 是人类领域 你将YellowPerson这个类进行修改的话,那么同样实现了Person的BlackPerson类要不要跟着修改 ,这很显然违反了单一原则的定义,所以是不行的。
05 依赖倒置原则-分析实战
05::01 什么是依赖倒置原则?
依赖于抽象,不能依赖于具体实现,即面向接口编程。
官方定义:
高模块不应该依赖于低模块,两者应依赖其抽象;
抽象不应该依赖细节,细节应该依赖抽象;
其中:
抽象就是接口或者抽象类,细节就是实现类。
通俗点就是针对抽象类层编辑,不要针对具体类进行编辑。
05::02 依赖倒置原则分析
举例需求: 现有一个客服,每天要接受微信上的消息。
代码实现:
//客服
class Worker
//接受消息
public void getMessage( Wx w)
w.setMessage();
//微信
class Wx
public void setMessage()
System.out.println("您好?");
public class Demo
public static void main(String[] args)
//举例需求: 现有一个客服,每天要接受微信上的消息,后续需求可能会新增钉钉消息、QQ消息
new Worker().getMessage(new Wx());
这样的代码能实现,但是如果后续需求在新增钉钉消息、QQ消息会怎么样,那是不是就不太好了,
我们这么改造一下,看一下效果:
// 引入接口 指定规范-消息的规范
interface Message
void setMessage();
//客服
class Worker1
//接受消息
public void getMessage( Message w)
w.setMessage();
//微信
class Wx1 implements Message
public void setMessage()
System.out.println("您好?");
//QQ
class Qq implements Message
public void setMessage()
System.out.println("哈喽!");
public class Demo1
public static void main(String[] args)
Message message = new Qq();
new Worker1().getMessage(message);
这样是不是好多了,这就是接口编程。
面向接口编程定义:
在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。
总结: 依赖倒置原则本质上就是通过抽象(抽象和接口) 使得各个类或者模块,实现彼此独立,互不影响,【实现模块间松耦合】,因此我们拿到需求后,要先【从顶层在细节的方式】来进行代码设计。
06 里氏替换原则-分析实战
06::01 什么是里氏替换原则?
简单定义:所有引用基类的地方必须能透明的使用子类的对象。
06::02 里氏替换原则分析
下面是一个违反里氏替换原则的一个例子:
class Arithmetic
public int test(int a,int b)
return a +b;
class NodeArithmetic extends Arithmetic
public int test(int a,int b)
return a - b;
我们能从上面看出子类已经改变父类原本的规则了,这明显违反了里氏替换原则。
因为父类 的一个方法完成的是一个加法的操作,而子类重写父类的该方法,重写成一个减法的操作,这种操作违反了里氏替换原则。
》》因为子类覆盖父类的时候,不能修改父类原有的功能,即子类可以扩展父类的功能,但不能改变原有父类的功能。
07 接口隔离原则-分析实战
07::01 什么是接口隔离原则?
类之间的依赖关系应该建立在最小的接口上面。
关注点:最小的接口上面。
通俗点说使用多个专门的接口来取代一个统一的接口。
简单点来说,设计的时候接口里面的方法太臃肿了,而当前场景下要使用的方法没有那么多,
但实现类继承该接口时必须将所有的方法都实现,这就造成了浪费,违反了最小接口这项规定,也就是违反了接口隔离原则。
07::02 接口隔离分析
下面是一个违反接口隔离的例子,我们来看一下:
public interface A
void method1();
void method2();
void method3();
void method4();
void method5();
//实际场景中使用的方法
class B
public void method1(A a)
a.method1();
public void method2(A a)
a.method2();
public void method3(A a)
a.method3();
class C implements A
@Override
public void method1()
System.out.println("method1");
@Override
public void method2()
System.out.println("method2");
@Override
public void method3()
System.out.println("method3");
@Override
public void method4()
@Override
public void method5()
我们观察后,可以得出实现A接口方法的实现类,必须要将1、2、3、4、5个方法都实现
//而实际场景中根本就没有用到4、5 方法,所以这个接口A设计的时候方法就有臃肿,就不是最小接口,因此违反原则。
我们来改造一下,即将A接口拆分成两个接口,根据实际需求,选择对应的那个接口进行传参,
这样实现类就可以避免实现多余的方法,符合接口隔离原则:
interface A1
void method1();
void method2();
void method3();
interface A2
void method3();
void method4();
//使用的时候,直接使用 A1接口即可,如下:
class D
public void method1(A1 a)
a.method1();
public void method2(A1 a)
a.method2();
public void method3(A1 a)
a.method3();
//这样实现类,继承A1即可,不会造成多余的浪费
class E implements A1
@Override
public void method1()
System.out.println("method1");
@Override
public void method2()
System.out.println("method2");
@Override
public void method3()
System.out.println("method3");
这样就不会有上述的问题了。
08 迪米特原则-分析实战
08::01 什么是迪米特原则?
简单定义:一个软件实体应尽可能少于其他实体发生相互作用,【核心目的就是降低耦合性】。
官方定义:
- 一个对象应该对其他对象有最少的了解,所以迪米特原则又叫最少知识原则;
也就是一个类对于自己依赖的类知道的越少越好。 - 只与直接的朋友进行通信;
也就是只要两个类有依赖关系,那么他们就是朋友关系,而直接的朋友就是:
- 一个类是以【成员变量】的身份出现在这个类上;
- 一个类是以【方法的参数类型】的身份出现在这个类上;
- 一个类是以【方法的返回值类型】的身份出现在这个类上;
即一个软件实体对其他实体的引用越少越好,或者说如果两个类不必彼此直接通信,
那么这两个类就不应该直接发生相互作用,而是通过引入一个第三者发生间接交互。
那什么是迪米特原则?
迪米特原则玩的就是类的关系,分析的就是类的依赖关系,凡是类中用到了对方,就说明两个类就具有依赖关系。
迪米特原则注意事项(重点):
- 迪米特原则的核心目的就是降低耦合性;
- 从被依赖者的角度说,尽量将逻辑封装在类的内部,避免对外泄漏,对外除了提供public方法,不泄露任何信息;
- 从依赖者的角度说,只依赖应该依赖的对象;
- 切忌为了用而用;
08::02 迪米特原则分析
下面是一个违反迪米特原则的实例:
需求:有一个学校,下面有各个学院和总部,现要求打印出总部的员工id和学院员工的id?
/**
* @description: TODO 学院员工 基类
* @author yangzhenyu
* @date 2022/2/18 18:50
* @version 1.0
*/
public class CollegeEmployee
private String id;
public CollegeEmployee(String id)
this.id = id;
public String getId()
return id;
public void setId(String id)
this.id = id;
/**
* @description: TODO 学院员工 管理类
* @author yangzhenyu
* @date 2022/2/18 18:52
* @version 1.0
*/
public class CollegeManager
public List<CollegeEmployee> getList()
ArrayList<CollegeEmployee> collegeEmployees = new ArrayList<>();
for (int i =0;i<3;i++)
collegeEmployees.add(new CollegeEmployee("学院员工 id:"+i));
return collegeEmployees;
/**
* @description: TODO 学校总部员工的基类
* @author yangzhenyu
* @date 2022/2/18 18:48
* @version 1.0
*/
public class SchoolEmployee
private String id;
public SchoolEmployee(String id)
this.id = id;
public String getId()
return id;
public void setId(String id)
this.id = id;
/**
* @description: TODO 学校总部 管理类 (违反迪米特原则实例)
* @author yangzhenyu
* @date 2022/2/18 18:51
* @version 1.0
*/
public class SchoolManager
public List<SchoolEmployee> getList()
ArrayList<SchoolEmployee> schoolEmployee = new ArrayList<>();
for (int i =0;i<3;i++)
schoolEmployee.add(new SchoolEmployee("学校总部员工 id:"+i));
return schoolEmployee;
public void print(CollegeManager manager)
//打印总部员工
this.getList().forEach(v->
System.out.println(v.getId());
);
System.out.println("===================================");
// 打印学院员工
List<CollegeEmployee> collegeEmployees = manager.getList();
collegeEmployees.forEach(v->
System.out.println(v.getId());
);
public class Demo
public static void main(String[] args)
new SchoolManager().print(new CollegeManager());
功能实现是没有问题的,但是对于迪米特原则来说SchoolManager 这个类中用了非直接朋友关系的对象,下面的是分析的代码:
public class SchoolManager
public List<SchoolEmployee> getList()
//SchoolEmployee 作为SchoolManager的方法的返回值类型,所以它们是直接的朋友关系
ArrayList<SchoolEmployee> schoolEmployee = new ArrayList<>();
for (int i =0;i<3;i++)
schoolEmployee.add(new SchoolEmployee("学校总部员工 id:"+i));
return schoolEmployee;
//CollegeManager 作为SchoolManager的方法参数类型 ,所以它们是直接的朋友关系
public void print(CollegeManager manager)
//打印总部员工
this.getList().forEach(v->
System.out.println(v.getId());
);
System.out.println("===================================");
// 打印学院员工
//CollegeEmployee 作为SchoolManager的方法内部出现 ,所以它们不是直接的朋友关系,
// 不符合迪米特原则的第二个规范,只与直接的朋友进行通信,避免非直接朋友的耦合关系
List<CollegeEmployee> collegeEmployees = manager.getList();
collegeEmployees.forEach(v->
System.out.println(v.getId());
);
问题就出现在CollegeEmployee 作为SchoolManager的方法
以上是关于-设计模式七大基本原则分析+实战+总结(详细)的主要内容,如果未能解决你的问题,请参考以下文章