大话设计模式之设计模式遵循的七大原则

 最近几年来,人们踊跃的提倡和使用设计模式,其根本原因就是为了实现代码的复用性,增加代码的可维护性。设计模式的实现遵循了一些原则,从而达到代码的复用性及增加可维护性的目的,设计模式对理解面向对象的三大特征有很好的启发,不看设计模式,很难深层地体会到面向对象开发带来的好处 。在刚开始学习中,很难做到将这些模式融汇贯通,所以这个需要我们在编码前多思考,等想充分了,在开始实践编码。下面是设计模式应当遵循的七大原则

1.开闭原则(Open Close Principle)

定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

    开放-封闭原则的意思就是说,你设计的时候,时刻要考虑,尽量让这个类是足够好,写好了就不要去修改了,如果新需求来,我们增加一些类就完事了,原来的代码能不动则不动。这个原则有两个特性,一个是说“对于扩展是开放的”,另一个是说“对于更改是封闭的”。面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。这就是“开放-封闭原则”的精神所在

    比如,刚开始需求只是写加法程序,很快在client类中完成后,此时变化没有发生,需求让再添加一个减法功能,此时会发现增加功能需要修改原来这个类,这就违背了开放-封闭原则,于是你就应该考虑重构程序,增加一个抽象的运算类,通过一些面向对象的手段,如继承、动态等来隔离具体加法、减法与client耦合,需求依然可以满足,还能应对变化。此时需求要添加乘除法功能,就不需要再去更改client及加减法类,而是增加乘法和除法子类即可。
绝对的修改关闭是不可能的,无论模块是多么的‘封闭‘,都会存在一些无法对之封闭的变化,既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。在我们最初编写代码时,假设变化不会发生,当变化发生时,我们就创建抽象来隔离以后发生同类的变化。

     我们希望的是在开发工作展开不久就知道可能发生的变化,查明可能发生的变化所等待的时候越长,要创建正确的抽象就越困难。开放-封闭原则是面向对象设计的核心所在,遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出现频繁变化的那些部分做出抽象,然而对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意,拒绝不成熟的抽象和抽象本身一样重要。开放-封闭原则,可以保证以前代码的正确性,因为没有修改以前代码,所以可以保证开发人员专注于将设计放在新扩展的代码上。

简单的用一句经典的话来说:过去的事已成历史,是不可修改的,因为时光不可倒流,但现在或明天计划做什么,是可以自己决定(即扩展)的。

2.里氏代换原则(Liskov Substitution Principle)

定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

定义2:子类型必须能够替换掉它们的父类型。
    描述:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别,也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化
例子:在生物学分类上,企鹅是一种鸟,但在编程世界里,企鹅却不能继承鸟。在面向对象设计时,子类拥有父类所有非private的行为和属性,鸟会飞,但企鹅不会飞,所以企鹅不能继承鸟类。

    只有当子类可以替换掉父类,软件单位的功能不受影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为,正是有里氏代换原则,使得继承复用成为了可能。正是由于子类型的可替换性才使得使用父类类型的模块在无需修改的情况下就可以扩展,不然还谈什么扩展开放,修改关闭呢

里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:

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

2.子类中可以增加自己特有的方法。

3.当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

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

    看上去很不可思议,因为我们会发现在自己编程中常常会违反里氏替换原则,程序照样跑的好好的。所以大家都会产生这样的疑问,假如我非要不遵循里氏替换原则会有什么后果?

后果就是:你写的代码出问题的几率将会大大增加。

3.依赖倒转原则(Dependence Inversion Principle)

定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程

    依赖倒转其实就是谁也不要依靠谁,除了约定的接口,大家都可以灵活自如。依赖倒转可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之那就是过程化的设计了。如果设计的各个部件或类相互依赖,这样就是耦合度高,难以维护和扩展,这也就体现不出面向对象的好处了。

    依赖倒转原则,好比一个团队,有需求组,开发组,测试组,开发组和测试组都是面对同样的需求后,做自己相应的工作,而不应该是测试组按照开发组理解的需求去做测试用例,也就是说开发组和测试组都是直接面向需求组工作,大家的目的是一样的,保证产品按时上线,需求是不依赖于开发和测试的。

    依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

    依赖倒置原则的中心思想是面向接口编程,传递依赖关系有三种方式,以上的说的是是接口传递,另外还有两种传递方式:构造方法传递和setter方法传递,相信用过Spring框架的,对依赖的传递方式一定不会陌生。

在实际编程中,我们一般需要做到如下3点:

低层模块尽量都要有抽象类或接口,或者两者都有。

变量的声明类型尽量是抽象类或接口。

使用继承时遵循里氏替换原则。

    总之,依赖倒置原则就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。

4.接口隔离原则(Interface Segregation Principle)

   接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。

   说到这里,很多人会觉的接口隔离原则跟单一职责原则很相似,其实不然。其一,单一职责原则原注重的是职责;而接口隔离原则注重对接口依赖的隔离。其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口接口,主要针对抽象,针对程序整体框架的构建。

采用接口隔离原则对接口进行约束时,要注意以下几点:

1. 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。

2. 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。

3. 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

   运用接口隔离原则,一定要适度,接口设计的过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。

4.组合/聚合复用原则

就是说要尽量的使用合成和聚合,而不是继承关系达到复用的目的
该原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分:新的对象通过向这些对象的委派达到复用已有功能的目的。
      其实这里最终要的地方就是区分“has-a”和“is-a”的区别。相对于合成和聚合,
继承的缺点在于:父类的方法全部暴露给子类。父类如果发生变化,子类也得发生变化。聚合的复用的时候就对另外的类依赖的比较的少。。
合成/聚合复用
① 优点:
新对象存取成分对象的唯一方法是通过成分对象的接口;
 这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不见的;

 这种复用支持包装;
这种复用所需的依赖较少;
每一个新的类可以将焦点集中在一个任务上;
 这种复用可以在运行时动态进行,新对象可以使用合成/聚合关系将新的责任委派到合适的对象。
② 缺点:
通过这种方式复用建造的系统会有较多的对象需要管理。

继承复用
① 优点:
  新的实现较为容易,因为基类的大部分功能可以通过继承关系自动进入派生类;
  修改或扩展继承而来的实现较为容易。
② 缺点:
  继承复用破坏包装,因为继承将基类的实现细节暴露给派生类,这种复用也称为白箱复用;
  如果基类的实现发生改变,那么派生类的实现也不得不发生改变;
  从基类继承而来的实现是静态的,不可能在运行时发生改变,不够灵活。
6.迪米特法则(Law Of Demeter)

    迪米特法则其根本思想,是强调了类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成影响,也就是说,信息的隐藏促进了软件的复用。

    自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。

    迪米特法则又叫最少知道原则,最早是在1987年由美国Northeastern University的Ian Holland提出。通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。

一句话总结就是:一个对象应该对其他对象保持最少的了解。

7.单一职责原则(Single Responsibility Principle)

定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责,应该仅有一个引起它变化的原因

    说到单一职责原则,很多人都会不屑一顾。因为它太简单了。稍有经验的程序员即使从来没有读过设计模式、从来没有听说过单一职责原则,在设计软件时也会自觉的遵守这一重要原则,因为这是常识。在软件编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。虽然单一职责原则如此简单,并且被认为是常识,但是即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。为什么会出现这种现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。

遵循单一职责原的优点有:

1.可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;

2.提高类的可读性,提高系统的可维护性;

3.变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都需要遵循这一重要原则。

 

转载自:http://blog.csdn.net/csh624366188/article/details/7459918

转载于:https://www.cnblogs.com/jiangdd/archive/2012/04/17/2454161.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379792.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IIC通信---EEPROM24C02---STMF4

IIC通信协议 IIC是同步半双工通信,一个数据线SDA和一个时钟SCL线,可以接受和发送数据。在CPU与被控IC之间、IC与IC之间进行双向传送。 空闲状态 IIC总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。 起始信号 当SCL为高…

实训09.08:简单的算法练习

/*final 关键字 修饰的变量值 后期不可更改 相当于定义常量常量 :不可更改*/final int a 10;//a 20; 报错的值不可更改!/*输入函数* */System.out.println("请输入数字:");Scanner scanner new Scanner(System.in);int b…

让自己闪亮

转载于:https://www.cnblogs.com/Gigabyte/archive/2009/01/03/you_can_shine.html

Java中的wait()和sleep()方法之间的区别

Java中的wait()和sleep()方法 (wait() and sleep() methods in Java) First, we will see how wait() method differs from sleep() method in Java? 首先,我们将看到wait()方法与Java中的sleep()方法有何不同? wait()方法 (wait() Method) This metho…

离线使用iPhone SDK文档的方法

在使用Xcode进行iPhone编程时,有时需要参考iPhone SDK的文档,不过每次ControlClick后,Xcode都会试图连接Internet,进行在线读取。有什么方法能够把资料下载到硬盘上进行离线阅读吗? 答案是肯定的。首先去Xcode的Prefer…

远程连接sql server 2000服务器的解决方案

远程连接sql server 2000服务器的解决方案2007-04-07 11:29远程连接sql server 2000服务器的解决方案   一 看ping 服务器IP能否ping通。   这个实际上是看和远程sql server 2000服务器的物理连接是否存在。如果不行,请检查网络,查看配置&#xff0c…

实训09.10:HTML简单表格设计

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>燕雨简历</title></head><body><table border"" cellspacing"" cellpadding"" width"400px" height"6…

LCD显示实验----STM32f4--HAL

步骤 LCD初始化 LCD_Init(); //LCD初始化此函数在lcd.c文件里面 2. 设置LCD背景颜色 LCD_Clear(WHITE);此函数在lcd.c文件里面 3. 设置字体颜色 POINT_COLORRED; 写入要显示的字体 LCD_ShowString(10,80,240,24,24,"LTDC TEST");LCD_ShowSt…

JavaScript | 使用提示从用户输入值

Example 1) Input name and print 示例1)输入名称和打印 Code (JS & HTML): 代码(JS和HTML)&#xff1a; <!DOCTYPE html><HTML><HEAD><SCRIPT>var name prompt("Enter Your name:");var msg "Welcome "name;//alert(msg)…

一个游戏程序员的学习资料 (zz)

一个游戏程序员的学习资料//z 2012-4-19 14:39:51 PM IS2120CSDN想起写这篇文章是在看侯杰先生的《深入浅出MFC》时, 突然觉得自己在大学这几年关于游戏编程方面还算是有些心得&#xff0c;因此写出这篇小文,介绍我眼中的游戏程序 员的书单与源代码参考。一则是作为自己今后两年…

项目管理中工作分解结构模型(WBSM)的应用

摘要 本文根据工作分解结构(WBS)的工作特点&#xff0c;运用系统工程的思想理论方法&#xff0c;构建了工作分解结构模型&#xff0c;并提出了模型算法;该模型方法的建立使得WBS工作更加简单可靠、思路清晰、基于更加可靠的科学基础之上。 1、工作分解结构模型(WBSM)方法工作程…

实训09.11:java重点内容介绍

package test;/** * OP:面向对象的简称* 类&#xff1a;同一特征的属性* * 类的定义&#xff1a;具有相同特征和行为的事物的抽象。&#xff08;不具体化&#xff09;* 对象&#xff08;实例对象&#xff09;&#xff1a;具体真实存在的实例。* 类是对象的实例&#xff1a;* *…

SPI通信原理---STM32F4--HAL

SPI接口原理 SPI是一种高速全双工同步通信&#xff0c;在芯片管脚上占用四根线&#xff0c;主要应用在EEPROM、FLASH、实时时钟、AD转换器&#xff0c;还有数字信号处理器和数字信号解码器之间。 SPI接口使用4根线通信。 MISO&#xff1a;主设备数据输入&#xff0c;从设备数…

Linux 引导管理器 grub2 使用简介

转自&#xff1a;杜昌彬的空间 首先向其致敬&#xff01;有改动。 grub是Linux系统即其他类unix系统的主流bootloder&#xff0c;由于grub原来版本的设计存在很大缺陷&#xff0c;与以前的grub很不相同&#xff0c;其使用和配置也发生很大变化。现在很多Linux发行版本都使用了…

pata1015_ATA / PATA的完整形式是什么?

pata1015ATA / PATA&#xff1a;高级技术附件/并行高级技术附件 (ATA/PATA: Advanced Technology Attachment/Parallel Advanced Technology Attachment) ATA is an abbreviation of Advanced Technology Attachment. ATA has existed for a long time with the name PATA. Whe…

产品

总结一下&#xff1a;  1、核心功能要做透&#xff0c;做的人家追不上&#xff0c;自己的优势要尽量的发挥&#xff1b;  2、产品口碑要建立&#xff0c;要关注高端用户&#xff0c;要调整自己心态&#xff1b;  3、敏捷、快&#xff0c;产品迭代要快&#xff0c;快速实现…

FreeRTOS在STM32F429上移植

准备工作 FreeRTOS系统源码基础工程&#xff0c;这里我们用跑马灯实验 1.在工程里面添加FreeRTOS源码 在工程里面新建一个名为FreeROTS的文件夹 将FreeRTOS源码添加到这个文件夹里面 protable里面只需留下Keil、MemMang、RVDS文件夹 2、向工程分组中添加文件 FreeRTOS_C…

C++中的指针与引用(转)

原文地址&#xff1a;http://www.cnblogs.com/skynet/archive/2010/09/22/1832911.html写在前面 指针和引用形式上很好区别&#xff0c;但是他们似乎有相同的功能,都能够直接引用对象&#xff0c;对其进行直接的操作。但是什么时候使用指针&#xff1f;什么时候使用引用呢&…

实训09.11:数据库一些简单操作

new Database 新建数据库 new Table 新建表 utf-8 编码格式 primary key 主键&#xff1a;特点&#xff1a;在表中是唯一的不可重复的&#xff0c;一般都是学号&#xff0c;编号 auto increment 自增&#xff0c;一般都把主键设置为自增 allow nul…

c语言中将整数转换成字符串_在C语言中将ASCII字符串(char [])转换为八进制字符串(char [])...

c语言中将整数转换成字符串Given an ASCII string (char[]) and we have to convert it into octal string (char[]) in C. 给定一个ASCII字符串(char [])&#xff0c;我们必须在C中将其转换为八进制字符串(char [])。 Logic: 逻辑&#xff1a; To convert an ASCII string t…