设计模式—六大原则

前言

      

    小编在编程的道路上可谓越陷越深,以致有点不能自拔,为什么呢?哈哈,因为小编在OO的道路上又前进了一个台阶呢!跨了一大步呀!又向专业化迈了一步!那叫一个开心!闲话不多说,咱们这就进入正题,今天来分享一下学习设计模式中的一些收获,小编的学习材料是程杰的《大话设计模式》,一本生活化的编程规范参考书。


正文:


什么是设计模式?


       设计模式(Design pattern)是软件工程的基石脉络,如同大厦的结构一样。设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。最初源于GOF的《设计模式》一书的出版,第一次将设计模式提升到理论高度,并将之规范化。该书提出了23种基本设计模式。时至今日,在可复用面向对象软件的发展过程中,新的设计模式仍然不断出现。


为什么要用设计模式?

    在学习设计模式之前在网上了解到有个别程序员说设计模式在实际使用中并没有什么卵用。小编对此有些不同的见解:设计的关键从来都不是设计模式,而是设计原则。一个好的设计并不需要死套哪些设计模式的,最重要的是阐述好OOP的设计原则,尽可能做到开放封闭,奔着高内聚低耦合的目标而去。设计模式也不应该为了设计而使用,而是当用遇到你不能优雅解决的问题时,再去看他的设计模式就有可能发现优雅的解决方法。普通程序员学方法,文艺程序员学创造方法的方法,你不能片面的否定设计模式的价值,实际上,通过学习这些方法,我们已经学会了创造方法的方法。


六大设计原则

    上面说到“设计的关键不是设计模式,而是设计原则”,那么设计模式的原则都有哪些呢?设计模式常用到六大原则,分别是:开放封闭原则、单一职责原则、依赖倒转原则、里氏代换原则、合成聚合复用原则和迪米特法则。


开放-封闭原则(Open-Closed Principle,OCP):


一句话解释:软件实体对扩展开放,而对修改关闭。使用频率5星。


详解:模块应尽量在不修改原(是“原”,指原来的代码)代码的情况下进行扩展。那么怎么扩展呢?我们看工厂模式“factory pattern”:假设中关村有一个卖盗版盘和毛片的小子,我们给他设计一“光盘销售管理软件”。

我们应该先设计一“光盘”接口。而盗版盘和毛片是其子类。小子通过“DiscFactory”来管理这些光盘。代码为:

[csharp]  view plain  copy
  1. public class DiscFactory  
  2.     {  
  3.        public static 光盘  
  4.        getDisc(Stringname)  
  5.          {  
  6.               return(光盘)Class.forName(name).newInstance();  
  7.           }  
  8.    }  
有人要买盗版盘,怎么实现呢?
[csharp]  view plain  copy
  1. public class 小子  
  2.    {  
  3.        public static void main(String[] args)  
  4.       {  
  5.            光盘 d = DiscFactory.getDisc("盗版盘");  
  6.            d.卖();  
  7.        }  
  8.   }  
     如果有一天,这小子良心发现了,开始卖正版软件。没关系,我们只要再创建一个“光盘”的子类“正版软件”就可以了,不需要修改原结构和代码。怎么样?对扩展开放,对修改关闭——“开闭原则”。
        工厂模式是对具体产品进行扩展,有的项目可能需要更多的扩展性,要对这个“工厂”也进行扩展,那就成了“抽象工厂模式”

单一职责原则(Single Responsibility Principle,SRP)



一句话解释:一个类只负责一个功能领域中的相应职责。使用频率4星(5星为满)。


详解:就一个类而言,引起它改变的原因应该只有一个。如果一个类继承的职责过多,就等于把这些职责耦合到了一起,一个职责的变化会削弱或抑制这个类完成其他职责的能力。软件设计真正要做的许多内容,就是发现职责并把职责互相分离。如果多于一个的动机去改变一个类,那么这个类就具有多于一个的职责,此时就应该考虑类的职责分离。


依赖倒转原则(Dependence Inversion Principle,DIP)



一句话解释:抽象不应该依赖于细节,细节应该依赖于抽象。使用频率5星。


详解:简单点说就是,针对接口编程,不要对实现编程。在软件里面,把父类都替换成它的子类,程序的行为没有变化。也就是说,子类型能够替换掉它们的父类型。依赖性倒转其实可以说是面向对象设计的标志,用哪种语言编程并不是很重要。


里氏代换原则(Liskov Substiution Principle,LSP)



一句话解释:所有引用基类对象的地方能够透明地使用其子类的对象。使用频率5星。


详解:里氏代换原则的意思是指如果调用的是父类的话,那么换成子类也完全可以运行。子类可以替换父类,而不受到影响,子类也可以在父类的基础上增加新的行为。比如:猫是继承动物类的,以动物身份具有吃、喝、跑、叫等行为,当某天我们需要狗、牛、羊也需要类似的行为,由于它们都是继承动物,所以除了更改实例化的地方,其他程序都不需要改动。

代码如下:
[csharp]  view plain  copy
  1. 动物 animal =new 猫;   //需求的变化,只需要将“猫”改为“狗、牛、羊”等别的动物,其他程序不需更改。  
  2.      animal.吃();  
  3.      animal.喝();  
  4.      animal.跑();  
  5.      animal.叫();  
可以说:里氏代换原则是继承复用的一个基础。

合成/聚合复用原则(Composite ReusePrinciple,CRP)



一句话解释:尽量使用对象组合,而不是继承来达到复用目的。使用频率4星。


详解:经常又叫做合成复用原则。合成/聚合复用原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的。它的设计原则是:要尽量使用合成/聚合,尽量不要使用继承。
          就是说要少用继承,多用合成关系来实现。例如:有几个类要与数据库打交道,写了一个数据库操作的类,然后别的跟数据库打交道的类都继承这个。结果后来,我修改了数据库操作类的一个方法,各个类都需要改动。“牵一发而动全身”!面向对象是要把波动限制在尽量小的范围。


迪米特法则(Law of Demeter,LoD):


一句话解释:一个软件实体应当尽可能少地与其他实体发生相互作用。使用频率3星。


详解:不要和陌生人说话,即一个对象应对其他对象有尽可能少的了解。也称“最少知识原则”


    说到这里,再回想一下前面说的6项原则,恰恰是告诉我们用抽象构建框架,用实现扩展细节的注意事项而已:单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;复用原则告诉我们尽量使用对象少用继承;迪米特法则告诉我们要降低耦合。而开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭。


如何去遵守这六个原则


    对这六个原则的遵守并不是是和否的问题,而是多和少的问题,也就是说,我们一般不会说有没有遵守,而是说遵守程度的多少。任何事都是过犹不及,设计模式的六个设计原则也是一样,制定这六个原则的目的并不是要我们刻板的遵守他们,而需要根据实际情况灵活运用。对他们的遵守程度只要在一个合理的范围内,就算是良好的设计。我们用一幅图来说明一下。


    图中的每一条维度各代表一项原则,我们依据对这项原则的遵守程度在维度上画一个点,则如果对这项原则遵守的合理的话,这个点应该落在红色的同心圆内部;如果遵守的差,点将会在小圆内部;如果过度遵守,点将会落在大圆外部。一个良好的设计体现在图中,应该是六个顶点都在同心圆中的六边形。


    在上图中,设计1、设计2属于良好的设计,他们对六项原则的遵守程度都在合理的范围内;设计3、设计4设计虽然有些不足,但也基本可以接受;设计5则严重不足,对各项原则都没有很好的遵守;而设计6则遵守过渡了,设计5和设计6都是迫切需要重构的设计。


小结:

    到这里,设计模式的六大原则就写完了。还有一个原则上文没有提及到——接口隔离原则,感兴趣的朋友可以查一下它的概念及适用情景。因为设计模式对编程人员来说,的确非常重要。正如有句话叫做一千个读者眼中有一千个哈姆雷特,如果大家对这六项原则的理解跟我有所不同,欢迎留言,大家共同探讨。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值