HIT软件构造《设计模式》部分总结

创造模式

创造模式关心的是对象类创造的过程应该遵循的原则。

里氏替换原则

继承必须确保超类所拥有的性质在子类中仍然成立

里氏替换原则(Liskov Substitution Principle,LSP)是面向对象的设计原则。通俗地讲,它指出了父类不能干的事子类也许也不能干,但父类能干的事子类必须能干。也就是说子类的规约一定要比父类强 。具体来说分为以下几个方面

  1. 子类的precondition弱于或等于父类
  2. 子类的post condition强于或等于父类
  3. 子类的异常应该与父类相等或为父类异常的子类型
例子

在面向对象编程中,正方形不是长方形的子类型,因为正方形的规约显然是强于长方形的。所以不能用正方形去继承长方形,这与大家印象中的逻辑关系是有区别的。

合成复用原则

在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

合成复用原则(Composite Reuse Principle,CRP)又叫组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)。它也是面向对象的设计原则,为弄清这个原则表明了什么意思,我们首先得了解软件复用的方式。

软件复用

通常一个类的复用有两种实现方式:继承复用与合成复用。

  1. 继承复用:利用继承实现对父类方法的复用(需遵循LSP)。可以看到继承非常简介且易实现,但它将父类暴露给了子类,属于白盒复用,在一定程度上降低了安全性。同时由于父类与子类耦合度太高,如做修改很容易产生意想不到的后果,牵一发而动全身,灵活度不高。
  2. 合成复用:利用委托机制,利用一个待复用方法的对象来调用这个方法。也即将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,如此达到复用的效果。可以看到这样的复用保证了类的封装性,属于黑盒复用,且复用灵活度高。

也就是说,我们应该优先用合成复用。

例子

在设计汽车类时,它拥有颜色、动力源等划分。如果使用继承复用,可以看到组合是非常多的,而且每次有一个新的颜色或动力源,就得重新创造一个类继承父类。如下图所示,这样的设计显然是不够好的。
在这里插入图片描述
而运用合成复用,通过将颜色类与动力源类封装入汽车类,可以得到划分更清晰、复用性更好的代码,如下图所示:
在这里插入图片描述

结构模式

结构模式关心的是对象类之间的结构与组成关系

适配器模式

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作,提供转换功能的称为适配器。

适配器模式(Adapter)是一种设计模式,它的目的是将某个类/接口转换为客户期望的其他形式,以解决接口不兼容的问题。它的关键点在于,需要开发的具有某种业务功能的组件在现有的组件库中已经存在,但它们与当前系统的接口规范不兼容,如果重新开发这些组件成本又很高,这时用适配器模式能很好地解决这些问题。

例子

用户希望输入一个长方形的左下角和右上角坐标来显示一个长方形,但接口输入却为长方形的左下角坐标与长和宽,这时候应该提供给用户一个适配器。
(这里读者应尽量说服自己:用户很难将他期望的输入方式转换为接口的输入方式,在软件构造中很多情况确实如此,尽管这个例子看起来很可笑)
在这里插入图片描述
下图为设计的适配器效果。
在这里插入图片描述

装饰模式

指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式

在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰模式(Decorator)来实现。实现方式为将待扩展对象纳入新对象中,使之成为新对象的一部分,新对象通过委托来调用带扩展对象的基础功能,而在新对象中实现新功能。

例子

装饰模式在 Java 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。
下面代码是为 FileReader 增加缓冲区而采用的装饰类 BufferedReader 的例子,FileReader 并没有读入一行的功能,这个时候通过装饰类 BufferedReader 的装饰来扩展功能。

BufferedReader in=new BufferedReader(new FileReader("filename.txtn));
String s=in.readLine();

门面模式

通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。

门面或外观(Facade)模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。想法是很自然的,如果给用户三个或更多的接口,为什么不将这些接口封装为一个接口送给用户呢?如下图,我们只需要提供给用户房产局接口就行了。
在这里插入图片描述

例子

如下图的两个helper类,将其封装为一个HelperFacade门面类提供给用户会更方便。
在这里插入图片描述
这里可以看到使用门面可以让代码更加清晰明了且封装性更强。
在这里插入图片描述

行为模式

行为模式关心代码的功能与行为如何分配给不同的类

策略模式

定义一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户

策略模式(Strategy)通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。这样一来,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等,使client根据需要动态切换算法。

例子

这个比较好理解,我们应该给一个Strategy设计多种解决方法以便用户选择,而不是直接在Strategy中写死代码。
在这里插入图片描述

模板模式

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

模板模式(Template Method)具体是指共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现,主要是使用继承和重写来实现模板模式。

例子

将公共部分放入OrderProcessTemplate,不同的Order实现放在不同的Order类中,通过重写来改变细微区别。
在这里插入图片描述

迭代器模式

提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示

迭代器(Iterator)模式是指在客户访问类与聚合类之间插入一个迭代器,这分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节。如 Java 中的 Collection、List、Set、Map 等都包含了迭代器。

例子

迭代器模式是很常见的模式,有的时候我们也可以自己改写迭代器来达到我们的遍历要求,也就是说迭代器模式将遍历行为与对象分离开,增强了封装性。如下图自定义迭代顺序,改写next()与hasNext():
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值