面向对象五大设计原则以及常见设计模式总结

版权声明:本文为博主原创文章,未经博主允许不得转载。如果感觉文章哪里写的不对或者存在疑问,欢迎留言,共同学习、进步! https://blog.csdn.net/ydm19891101/article/details/84227061

尽管本人已经从事OOP编程好几年,但对于OOP编程的很多精髓依旧了解不深。加之最近项目不紧,特抽出时间总结一些面向对象设计原则以及设计模式的相关内容,加深自己的理解同时也希望可以帮到其他人。

note:编程是一门技术更是一门艺术,艺术来源于生活又高于生活。下面介绍的很多东西很多都可以和我们的日常生活紧密结合起来,建议大家从身边寻找原型。

一、三大特性

面向对象的三大特性:封装、继承、多态。

封装:封装变化点,对上游透明化设计,解耦上下游之间的依赖

继承:抽象出父类,将父类作为子类的模板,所有重复的代码都应该提到父类中去,而不是在每个子类中都重复。子类拥有父类所有非private的行为和属性。注意,不要滥用继承。

多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,多态其实部分破坏了封装的特性。

开发人员应该仅对程序中频繁呈现出变化的那部分进行抽象,然而,抽象不是无限度的,拒绝抽象和抽象本身一样重要。

降低软件各个层级之间的耦合度,将业务逻辑与界面逻辑分开,降低他们之间的耦合度,只有分离开,才可以达到容易维护和扩展。

封装、继承、多态也是为了降低程序的耦合度。

二、五大设计原则(SOLID原则)

1、单一职责原则(SRP)

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

职责可以理解为变化点。

该原则可以带来以下几点好处:

(1)降低类维护的难度

(2)降低耦合度,避免职责之间的相互影响

(3)降低类的复杂度

(4)降低单元测试难度,方便效果回归
 

2、修改-封闭原则(OCP)

对于扩展是开放的,对于修改是封闭的,对于修改封闭是为了避免修改会对之前的功能有影响。

面对需求,对于程序的改动是通过新增代码实现的,而不是更改现有的代码。

该原则是面向对象设计的核心所在,遵从这个原则可以带来面向对象所谓的可维护、可扩展、可复用、灵活性强的优点。

3、依赖倒置原则(DIP)

抽象不应该依赖于细节,细节应该依赖于抽象。简单点说就是要针对抽象(接口)编程而不是实现编程。

A:高层模块不应该依赖于低层模块,两个都应该依赖于抽象,可以是接口或者抽象类的抽象

B:抽象不应该依赖于细节,细节应该依赖于抽象。

4、里氏替换原则(LSP)

在软件里面,把父类替换成子类,程序的行为没有变化。简单点说,子类型必须能够替换掉他们的父类型。

包含以下4层含义:

(1)子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法

(2)子类中可以增加自己特有的方法

(3)当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松

(4)当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格

5、接口分离原则(ISP)

控制各个模块之间通过接口进行调用,防止直接调用。

无论哪种设计模式,都是围绕上面的五个原则展开的。

一个好模式(架构)的特点:易维护、易扩展、易复用,高内聚、都耦合,这样可以最大限度的做到易维护、易扩展、已复用。

三、常见设计模式:

1、简单工厂模式

对于上层屏蔽创建对象的细节,提供一种对象创建的接口,根据具体的策略创建对应的对象,最终给上层返回的是一个对象。

通常各个对象之间是有关系的,继承自相同的父类或者有继承链关系,只有这种在上次调用的时候才可以屏蔽这些不同对象直接方法调用的差异,调用同一个方法。

2、策略模式

封装算法,对上层屏蔽算法的实现细节。

应用场景:在不同的时间应用不同的业务规则。

3、代理模式

为其他对象提供一种代理以控制对这个对象的访问。

代理对象对上层隐层调用细节,代理对象的低层还是由原始者发起请求。

代理对象与被代理对象通常会实现相同的接口(抽象类),代理对象的方法体内实际还是调用了被代理对象的对应方法。

4、工厂方法模式

对于计算器工厂类而言,如果想要新增一个运算,需要修改工厂类以及新增一个运算类,而修改工厂类是违反扩展开发原则的。

工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

简单工厂模式是只有一个工厂类,而工厂方法是提供一个接口,然后衍生出多个子类工厂去实现该接口,在子类工厂里面决定具体使用哪个类型进行对象的实例化。

对应到计算器,就是提供加减乘除四个工厂类,在四个工厂类中具体实例化加减乘除操作类。如果还需要新增一个取模运算,只需要实现接口生成一个新的取模工厂类,然后在该工厂里实例化取模操作类(该类也要新增)。

5、原形模式

用原形实例指定创建对象的种类,并且通过拷贝这些原形创建新的对象。

原形模式的核心是拷贝,通过拷贝避免了通过构造函数创建对象,对性能有提升。

目前PHP语言里面的引用复制即是采用的该种方式:与原对象指定同一块地址单元,只有当对象的属性值发生变化时才会为其分配一块新的内存单元,阻止或推迟了对象内存单元的分配。

6、模板方法模式

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构I课重定义该算法的某些特定步骤。

该模式是通过把不变的行为搬移到超类中,去除子类中的重复代码来体现它的优势,提供了一个很好的代码复用的平台。

7、外观(门面)模式

为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这个子系统更加容易使用。

8、建造者模式

将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。

将构造细节对上层屏蔽,上层只需要关注与细节即可。

9、观察者模式

观察者模式又叫做发布-订阅模式。

该模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生改变时,会通知所有观察者对象,使他们能够自动更新自己。

观察者订阅主题对象(通知者)发布的状态变更并及时更新自己的状态。

该模式所做的工作其实就是在解耦,让耦合的双方都依赖于抽象而不是依赖于细节。从而使得各自的变化都不会影响另一边的变化。

一般用一个抽象类来定义主题对象(通知者),这个抽象类中存储了订阅了该主题对象的观察者,并可以随时增加/移除观察者,并在状态变更时向订阅者发布消息。可以实现多个子类来产生多个发布者(通知者)。

一般也用一个抽象类来定义观察者,这个类中定义了观察者订阅的发布者(抽象类),以及接收到发布者发送的通知时如何响应,具体响应的内容由各个子类去实现。

10、抽象工厂模式

提供一个创建一系列相关或者相互依赖对象的接口,无需指定他们具体的类。

11、状态模式

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

12、适配器模式

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的哪些类可以一起工作。

C#中关于数据源 数据库有DataAdapter适配器。

适用场景:双方都不太容易修改的时候再使用适配器模式适配,可以用于开发设计和项目维护阶段。

13、迭代器模式

提供一种方法顺序访问一个聚合对象中各个元素,而不暴露该对象的内部表示。

各个语言中的foreach for遍历即是常见的迭代器模式运用。

14、单例模式

保证一个类仅有一个实例,并提供一个访问访问它的全局访问点。

在类中定义一个私有的构造函数和对象变量,并提供一个public类型的静态方法,在这个静态方法中完成对象是否创建的判断(根据对象变量判断)以及创建。

多线程并发访问时可能会造成多个对象的产生,可以通过锁来解决。

15、桥接模式

将抽象部分与他的实现部分分离,使他们都可以独立地变化。

16、解释器模式

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中句子。

浏览器就是html语言以及js语言的解释器,php-cgi就是php语言的解释器。

上面只是简要列举了一些常见的设计模式,具体各个设计模式如何使用后期会逐步完善。


 

猜你喜欢

转载自blog.csdn.net/ydm19891101/article/details/84227061