秉着温水煮青蛙,优胜劣汰的思想,想换个公司提升一下技术。结果裸辞两个月了,依然没有找到工作。在几次的面试过程中感受到了自己技术的不足,于是痛定思痛,决定沉静下来好好复习总结一下以前学过的知识。为什么决定复习设计模式呢?这里就要谈到设计模式的用处,或者为什么要学习设计模式?
- 看懂源代码:如果不懂设计模式去看Jdk、Spring、SpringMVC、IO等等等等的源码,会很迷茫,寸步难行。
- 为了让程序有更好的代码重用性(相同功能的代码,不用多次编写)、可读性(编程规范性,便于程序员的阅读理解)、可扩展性(当需要增加新的功能时,非常方便)、可靠性(当我们增加新的功能后,对原来的功能没有影响),使程序呈现高内聚、低耦合的特性。
文章目录
什么是设计模式
设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。
设计模式分类
模式分类 | 描述 |
---|---|
创建型模式 | 工厂模式 抽象工厂模式 单例模式 建造者模式 原型模式 |
结构型模式 | 适配器模式 桥接模式 过滤器模式 组合模式 装饰器模式 外观模式 享元模式 代理模式 |
行为型模式 | 责任链模式 命令模式 解释器模式 迭代器模式 中介者模式 备忘录模式 观察者模式 状态模式 空对象模式 策略模式 模板模式 访问者模式 |
设计模式的原则
设计模式原则,其实就是程序员在编程时,应当遵守的原则,也是设计模式的基础
1、单一职责原则
原则思想:一个方法只负责一件事情。
优点:降低类和类的耦合,提高可读性,增加可维护性和可拓展性,降低可变性的风险。
注意事项:
- 降低类的复杂度,一个类只负责一项职责
- 提高类的可读性,可维护性
- 降低变更引起的风险
曾经在这个原则上吃过大亏,做一个预想单,有三种不同的预想单,但是用的是同一个service、dao、entity,通过if-else判断type字段是哪种预想单,然后处理,结果因为修改service里面其中一个预想单,导致其他预想单也报错,这就是违反了单一职责原则的后果,耦合度太高了!
2、接口隔离原则
原则思想:不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上
例如:
接口Interface 有五个方法1、2、3、4、5,类A通过接口Interface依赖类B,类C通过接口Interface依赖类D,但是类A只需要接口的1、2、3方法,而类C只需要接口的1、4、5方法,接口Interface对于类A和类C来说不是最小接口。按隔离原则应该这样处理:
将接口Interface拆分为独立的几个接口(这里拆分成3个接口),类A和类C分别与他们需要的接口建立依赖关系,也就是采用接口隔离原则
3、依赖倒转原则
原则思想:
- 高层模块不应该依赖低层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 依赖倒转的中心思想是面向接口编程
设计理念:相对于细节的多变性,抽象的东西要稳定的多。在Java中,抽象指的是接口或抽象类,细节就是具体的实现类
注意事项:
- 低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性好
- 变量的声明类型尽量是抽象类或接口,这样变量引用和实际对象间,就存在一个缓冲层,利于程序的扩展和优化
- 继承时遵顼里氏替换原则
public class DependecyInversion {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
}
}
class Email{
public void getInfo(){
System.out.println("电子邮箱消息:hello!");
}
}
class Person{
public void receive(Email email){
email.getInfo();
}
}
存在问题:如果我们获取的对象是微信,短信等等,则新增类,同时Person也要新增相应的接收方法
解决思路:引入一个抽象接口IReceiver,表示接收者,这样Person类与接口IReceiver发生依赖
public class DependecyInversion {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Email());
person.receive(new WeiXin());
}
}
interface IReceiver{
public void getInfo();
}
class Email implements IReceiver{
public void getInfo(){
System.out.println("电子邮箱消息:hello!");
}
}
class WeiXin implements IReceiver{
public void getInfo(){
System.out.println("微信消息:hello!");
}
}
class Person{
public void receive(IReceiver iReceiver){
iReceiver.getInfo();
}
}
依赖关系传递的三种方式:
- 接口传递
- 构造方法传递
- setter方式传递
4、里氏替换原则
原则思想:使用的基类可以在任何地方使用继承的子类,完美的替换基类。
大概意思:子类可以扩展父类的功能,但不能改变父类原有的功能。子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法,子类中可以增加自己特有的方法。
在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法,里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖来解决问题。
5、开闭原则(最基础、最重要的设计原则)
原则思想:一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。编程中遵循其他原则,以及使用设计模式的目的就是遵循开闭原则。
我的理解:在程序使用jar包的时候,jar包的提供方应该是扩展开放的,但是如果因为提供方升级修改了jar包,而导致使用其jar包的使用方也要修改代码的话,使用方就会特别难受!
6、迪米特法则
原则思想:一个对象应该对其他对象保持最小的了解
设计理念:类与类关系越密切,耦合度越大
迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。迪米特法则还有一个简单的定义:只与直接的朋友通信。
直接的朋友:我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量的类不是直接的朋友,也就是说,陌生的类不要以局部变量的形式出现在类的内部
注意事项:
- 迪米特法则的核心是降低类之间的耦合
- 但是要注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低类间(对象间)耦合关系,并不是要求完全没有依赖关系
7、合成复用原则(有些地方没有)
原则思想:尽量使用组合/聚合的方式,而不是使用继承
- 聚合关系(Aggregation)体现的是A对象可以包含B对象,但B对象不是A对象的组成部分。具体表现为,如果A由B聚合成,表现为A包含有B的全局对象,但是B对象可以不在A创建的时刻创建。
- 组合关系(Composition):如果A由B组成,表现为A包含有B的全局对象,并且B对象在A创建的时刻创建。
人与身体的各个部位就是组合关系,身体的各个部位组成了人。人和身份证就是聚合关系,没有身份证,人也还是完整的。
设计原则核心思想
- 找出应用中需要变化的地方,把它们独立起来,不要和那些不需要变化的代码混在一起
- 针对接口编程,而不是针对实现编程
- 为了交互对象之间的松耦合设计而努力