软件构造:面向可复用性和可维护性的设计模式


    在我们写完一份软件之后,我们往往需要对这份软件进行后续的更新与维护,同时我们也希望在后续的软件编写的过程中利用到之前编写的内容,进行软件的服用。因此,本片聚焦于几种面向可复用性和可维护性的设计模式,介绍设计的几种方法。
一、创建型模式:

1.工厂方法模式:

    工厂方法模式由抽象工厂、具体工厂、抽象产品和具体产品等4个要素构成。抽象工厂:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。抽象产品:定义了产品的规范,描述了产品的主要特性和功能。具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

    优点:

        a.用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。

        b.灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。

        c.典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

    缺点:

        a.类的个数容易过多,增加复杂度

        b.增加了系统的抽象性和理解难度

        c.抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

    应用场景:

        a.客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。

        b.创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。

        c.客户不关心创建产品的细节,只关心产品的品牌

二、结构型模式:

1.适配器模式:

    适配器模式的定义是:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

    按照我的理解来讲,适配器就是当客户端调用的方法与实现方法的形式不一样时,我们再设计另外一个接口,对客户端给出的参数进行一定程度的处理,然后再正常调用已经实现了的方法。举个栗子,比如我们设计一个计算矩形面积的类,已经实现的方法是通过输入长和宽来计算面积。然而客户端给出的确实左上角的顶点和右下角的顶点的坐标。这时,我们可以设计一个adapter接口,通过顶点坐标计算出长和宽,再计算面积。这就是适配器模式

    优点:

        a.客户端通过适配器可以透明地调用目标接口。

        b.复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。

        c.将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。

        d.在很多业务场景中符合开闭原则。

    缺点:

        a.适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性。

        b.增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。

2.装饰器模式:

    在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。通过递归的方式对每一个特性构造子类,通过委派机制增加到对象上。这一种模式可以想象成给一个已经实现的类不断地“穿衣服”。例如,课上我们所讲的冰淇淋类的例子。我们先实现了一个原味冰淇淋的类PlainIceCream,然后我们可以构造实现IceCream接口的另一个类,也就是修饰类。在这个修饰类中增加IceCream类的参数,并添加一些诸如加糖果、坚果等功能。这样不断套娃,可以实现功能的叠加。这也是装饰器模式得名的原因。

    优点:

        a.装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用

        b.通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果

        c.装饰器模式完全遵守开闭原则

    缺点:

        a.装饰器模式会增加许多子类,过度使用会增加程序得复杂性。

三、行为类模式:

1.策略模式:

    有多种不同的算法来实现同一个任务,但需要client根据需要动态切换算法,而不是写死在代码里。为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例。策略模式是关于ADT内部的设计,这点要区分于visitor模式

    优点:

        a.算法可以自由切换。

        b.避免使用多重条件判断。

        c.扩展性良好。

    缺点:

        a.策略类会增多。

        b.所有策略类都需要对外暴露。

2.迭代器模式:

    客户端希望对放入容器/集合类的一组ADT对象进行遍历访问,而无需关心容器的具体类型,也就是说,不管对象被放进哪里,都应该提供同样的遍历方式。

    优点:

        a.它支持以不同的方式遍历一个聚合对象。

        b.迭代器简化了聚合类。

        c.在同一个聚合上可以有多个遍历。

        d.在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

    缺点:

        a.由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

    应用场景:

        a.访问一个聚合对象的内容而无须暴露它的内部表示。

        b.需要为聚合对象提供多种遍历方式。

        c.为遍历不同的聚合结构提供一个统一的接口。

3.访问者模式:

    在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。这种模式同样是通过委托实现的。具体实现方法如下:假设我们现在已经有一个类实现了一系列的功能,现在我们想要添加一个新方法。这时,我们可以在原类中添加一个accept(visitor)方法,并且添加visitor委托参数,然后在该方法中将自己this作为参数调用visitor中的方法。这样我们可以在visitor中设计新的功能,而不改变原有的ADT。这就是访问者模式。

    优点:

        a.符合单一职责原则

        b.优秀的扩展性

        c.灵活性

    缺点:

        a.具体元素对访问者公布细节,违反了迪米特原则

        b.具体元素变更比较困难

        c.违反了依赖倒置原则,依赖了具体类,没有依赖抽象

    应用场景:

        a.对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作

        b.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作”污染”这些对象的类,也不希望在增加新操作时修改这些类

原创文章,作者:bd101bd101,如若转载,请注明出处:https://blog.ytso.com/267325.html

(0)
上一篇 2022年6月15日
下一篇 2022年6月15日

相关推荐

发表回复

登录后才能评论