设计模式之七大设计原则1
设计模式之七大设计原则
在编写软件的过程中,程序员面临着来自耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性
等多方面的挑战。
设计模式常用的七大设计模式:
-
单一职责原则
-
接口隔离原则
-
依赖倒转(倒置原则)
-
里氏替换原则
-
开闭原则
-
迪米特法则
-
合成复用原则
接下来我们就来详细讨论一下这七种设计原则
一、单一职责原则(Single Responsibility Principle )
对类来说,即一个类应该只负责一项职责。
用类实现单一职责
将类分解,根据不同的职责创建不同的类
这种方法会分解类,在复杂场景下应用的比较多。但在简单场景将类分解会加大开销。
用方法实现单一职责
这种方式使得每一个方法对应一种职责,从而实现了单一职责。
public class SingleResponsibility1{
public static void main(String[] args){
Vehicle2 vheicle2 = new Vehicle2();
vehicle2.run("汽车");
vehicle2.runAir("飞机");
vheicle3.runWater("轮船");
}
}
class Vehicle2{
public viod run(String vehicle){
System.out.println(vehicle + "公路上跑")
}
public viod runAir(String vehicle){
System.out.println(vehicle + "天上飞")
}
public viod runWater(String vehicle){
System.out.println(vehicle + "水上漂")
}
}
单一职责原则注意事项和细节
-
降低类的复杂度,一个类只负责一项职责。
-
提高类的可读性,可维护性。
-
降低变更带来的风险。
-
通常情况下,我们应该遵守单一职责原则,只有逻辑足够简单,才能在代码级别违反单一职责原则;
只有类中方法数量足够少,可以在方法级别上保持单一职责原则。
二、接口隔离原则(Interface Segregation Principle)
基本介绍
客户端不应该依赖它不需要的接口,即一个类对另一个的依赖应该建立在最小的接口上。

按照隔离原则应该将Interface_1拆分为独立的几个接口。

三、依赖倒转原则(Dependence Inversion Principle)
基本介绍
-
高层模块不应该依赖低层模块,二者都应该依赖抽象
-
抽象不应该依赖细节,细节应该依赖抽象
-
依赖倒转原则的中心思想是面向接口编程
-
依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比
以细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类.
-
使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。
应用实例
- 不满足依赖倒转原则实例
public class DependenceInversion1{
public static void main(String[] args){
Person Person = new Person();
person.receive(new Email);
}
}
class Email{
public String getInfo(){
return "电子邮件信息:hello,world";
}
}
//完成Person接收消息的功能
class Person{
public void receive(Email email){
System.out.println(email.getInfo());
}
}
代码分析:
简单,易得到
如果我们获取的对象是微信,短信等等,则新增类,同时Person也要新增接收方法
-
改进方法
思路:引入一个抽象的接口IReceiver,表示接收者,这样Person类与接口IReceiver发生依赖,因为Email,WeiXin
等等属于接收的范围,它们各自实现IReceiver接口就可以,这样设计之后,我们就符合依赖倒转原则。
代码实现:
public class DependenceInversion2{ public static void main(String[] args){ Person Person = new Person(); person.receive(new Email); person.receive(new WeiXIn); } } //定义一个接口 interface IReceiver{ public String getInfo(); } class Email implement IReceiver{ public String getInfo(){ return "电子邮件信息:hello,world"; } } //增加微信 class WeiXIn implement IReceiver{ public String getInfo(){ return "微信信息:hello,WeiXin"; } } //完成Person接收消息的功能 class Person{ public void receive(IReceiver receiver){ System.out.println(receiver.getInfo()); } }
依赖关系传递的三种方式
- 通过接口传递实现依赖
- 通过构造方法依赖传递
- 通过setter方法传递
四、里氏替换原则(Liskov Substitution Principle)
OO中的继承性的思考和说明
-
继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是再设定规范和契约,虽然它不强制要
求所有的子类必须遵守这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系
造成破坏。
-
继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植
性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须要考虑到
所有的子类,并且父类修改后,所有涉及到子类的功能都可能产生故障。
-
问题提出:在编程中,如何正确使用继承?--> 里氏替换原则
基本介绍
-
如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都
换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型,换句话说,所有引用基类的地方
必须能够透明地使用其子类的对象。
-
在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类中的方法。
-
里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依
赖来解决问题。
案例分析
-
不符合里氏替换
在子类中重写了父类的方法,改变了方法的功能,导致方法调用混乱。
//不符合里氏替换的实现
public class Liskov1{
public static void main(String[] args){
}
}
//A类
class A{
//返回两数之差
public int func1(int num1,int num2){
return num1-num2;
}
}
//B类
class B extend A{
//这里重写了A类的方法
public int func1(int a, int b){
return a + b;
}
public int func2(int a, int b){
return func1(a + b) + 9;
}
}
-
里氏替换的实现
创建一个更加基础的的基类,把更加基础的方法和成员写到base类。A类和B类之间通过聚合,组合等方式建立
联系。B类不再继承A类,所以方法功能的使用不会混淆。
![聚合]()
// 符合里氏替换的方式 public class Liskov2{ public static void main(String[] args){ } } //base类 class base{ } //A类 class A extends Base{ //返回两数之差 public int func1(int num1,int num2){ return num1-num2; } } //B类 class B extend base{ private A a = new A(); public int func1(int a, int b){ return a + b; } public int func2(int a, int b){ return func1(a + b) + 9; } public int func3(int a,int b){ return this.a.func1(a,b); } }
五、开闭原则(Open Closed Principle)
基本介绍
-
开闭原则是编程中最基础、最重要的设计原则。
-
一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,
用实现扩展细节。
-
当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码实现变化。
-
编程中遵守其他的原则,最终都是为了实现开闭原则。开闭原则是核心原则。
案例分析
-
普通实现,不考虑开闭原则
如果要新增一个图形,例如新增一个三角形类,那么就要在
GraphicEditor类中进行更改,也就是用户端也得修改,违反了开闭原则。
public class OCP1{
public static void main(String[] args){
}
}
//绘图类
class GraphicEditor{
//接受shape对象,然后根据style,来绘制不同的图形
public void drawShape(Shape s){
if(s.m_type == 1)
drawRectangle(s);
else if (s.m_type == 2)
drawCircle(s);
}
public void drawRectangle(Shape r){
System.out.println("绘制矩形");
}
public void drawCircle(Shape r){
System.out.println("绘制圆形");
}
}
class Shape{
int m_type;
}
class Rectangle extends Shape{
Rectangle(){
super.m_type = 1;
}
}
class Circle extends Shape{
Circle(){
super.m_type = 2;
}
}
-
使用开闭原则进行实现
思路:把创建Shape类做成抽象类,并提供一个抽象的draw方法,让子类去实现即可,这样使得我们有新
的图形需要扩展的时候,只需要让新的图形类继承Shape,并实现draw方法即可,这样使用方不需要修改
代码。
public class OCP2{
public static void main(String[] args){
GraphicEditor graphicEditor = new GraphicEditor();
graphicEditor.drawShape(new Circle());
}
}
//绘图类
class GraphicEditor{
//接受shape对象,然后根据style,来绘制不同的图形
public void drawShape(Shape s){
s.draw();
}
}
// 基类
abstract class Shape{
int m_type;
public abstract draw();//抽象方法
}
class Rectangle extends Shape{
Rectangle(){
super.m_type = 1;
}
public void draw(){
System.out.println("绘制矩形");
}
}
class Circle extends Shape{
Circle(){
super.m_type = 2;
}
public void draw(){
System.out.println("绘制圆形");
}
}
六、迪米特法则(Demeter Principle)
基本介绍
-
一个对象应该对其他的对象保持最少的了解。
-
类与类关系越密切,耦合度越大。
-
迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多
么复杂,都尽量将逻辑封装在类的内部。对外部除了提供的public方法,不对外泄露任何信息。
-
迪米特法则还有个更简单的定义:只与直接点的朋友通信。
-
直接的朋友:每个对象都会与其他的对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间
是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现在成员变量,方法参数,方法
返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部
变量的形式出现在类的内部。
实现方法
将一些实现方法放入本身的类内部,而不要在本身的类内对另一个类的对象进行方法的构造。
迪米特法则的注意事项
- 迪米特法则的核心思想是降低类之间的耦合。
- 降低耦合并不意味着没有耦合,依赖关系是会存在的。
七、合成复用原则(Composite Reuse Principle)
基本介绍
原则上是尽量少的去使用继承,而是采用聚合、组合等方式,从而降低了耦合度。
实现方法

小结
设计原则的核心思想:
- 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混合在一起。
- 针对接口编程,而不是针对具体实现编程。
- 为了交互对象之间的松耦合设计而努力。

浙公网安备 33010602011771号