设计模式之开篇原则(一)

设计模式到底是什么?它是对整个软件系统的拆分,组装,并决定模块间关系以及如何互动的方式。究其本质,设计模式就是以封装、继承、多态、抽象的语言特性为基础,以六大设计原则的灵魂组合而总结出的一系列优化方案。本篇文章主要讲的是设计模式之六大基本原则:单一职责、开闭原则、里式替换、依赖倒置、接口隔离、迪力米特里原则

单一职责

我们知道功能完备的软件系统是复杂的,系统的拆分与模块化是不可或缺的,而面向对象是以类来划分模块边界的,也就是说每个类都代表着一个功能角色模块,其职责应该是单一的,不是自己分内的事不应该负责,这就是单一职责原则。

举个例子,灯泡一定是可以亮和灭的,我们定义一个灯泡类并且包含“功率属性”以及“通电”和“断电”两个功能方法,这便是对灯泡的封装,一对大括号“{}”定义了其类模块的边界。

虽然说我的领域我做主,但绝不可肆意妄为。比如现在客户要求这个灯泡可以闪烁的霓虹灯效果,我们该怎样实现?直接在电灯类里再封装一堆逻辑电路控制其闪烁,比如新加一个flash()方法,并不停来回调用通电断电?这显然是错误的,灯泡就是灯泡,它只能亮和灭,能不能闪烁不是灯泡的职责,既然进行分类,就不要不伦不类。所以我们需要把闪烁控制电路独立出来,它们之间的通信应该通过接口去调用,划清界限,各司其职,这才是类封装的意义。

单一职责原则规定,对任何类的修改只能有一个原因。例如我们的灯泡类,它的职责就是照明,与其无关的一切修改动机都不予考虑。所以说灯泡绝不能封装与其本身职责不相干的功能,这样就保证其职责的单一性原则,类与类之间有明确的职责划分。

开闭原则

开闭原则,其中“开”指的是对扩展是开放的,”闭“则指的是对修改是关闭。通俗来讲就是不要修改已有的代码,而是去写新的代码。这对于已经上线并稳定运行的软件项目来说更为重要,修改代码的代价是巨大的,小小一个修改有可能会造成整个系统瘫痪,因为其可能会波及到的地方变得不可预知,难以估量。

举个简单的例子,我们有一个笔类用来画画,它有一个很简单的draw方法。这时业务扩展,需要画各种颜色的画,难道我们继续修改这个笔类的draw方法去接受颜色参数并加入大量逻辑判断吗?如果后期又需要水彩、水墨、油画等等颜料效果就需要没完没了的对笔进行代码修改,大量的逻辑代码会堆积在这个类中,就像拆开封装的机器壳子对内部电路二次修改,各种导线焊点杂乱无章、臃肿不堪。

造成这种局面肯定是系统设计上的问题,我们要对其重新审视,对笔类进行抽象,定义好一个绘画行为draw(),但具体怎样画不应予以关心。如此便建立了软件体系的高层抽象,如果后期要进行扩展,那么去添加新类并继承我们的高层抽象即可,各种笔保证了各自的特性,你画你的,我画我的。所以说开闭原则是通过抽象去实现的,高层的泛化保证了底层实现的多态化扩展

里氏替换

此原则指出是任何父类出现的地方子类一定也可以出现,换个角度讲也就是说一个优秀的设计中有引用父类的地方,一定可以用子类进行替换。其实面向对象设计语言的特性”继承与多态“正是为此而生,而我们在设计的时候一定要考虑到这一点,写框架代码的时候要面向抽象编程,而不是深入到具体子类中去,这样才能保证子类多态的可能性。

假设我们定义有这么一个类“禽类”,给它加一个飞翔方法fly(),于是客户端可以自由自在地调用其飞翔方法。不巧某天需要鸵鸟加入禽类的行列,可惜地是鸵鸟并不会飞,这下就闹得整个鸡飞狗跳,此时客户端就不能调用禽类的飞翔方法了,因为这个禽类有可能就是鸵鸟,这就违反了里氏替换原则。我们意识到最初的设计一定是有问题的,因为不是所有“禽类”都会“飞”,所以对于禽类不该有飞翔方法。

我们这里提供一种思路做重构,把禽类的飞翔方法抽离出去给一个接口Flyable,这样鸵鸟依旧可以继承禽类,对于其他可以飞的鸟则是继承禽类并实现Flyable接口。这样一来,客户端如果用的是禽类,那一定是鸟而绝不是兽,但不一定能飞,比如是鸵鸟或者火鸡;而如果用的是Flyable那它就必然能飞,也许是蝙蝠(兽类)甚至可以是飞机,这些子类一定是在其基类定义范围内可以随意替换而不引起任何系统问题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章