设计模式(1) -- 设计模式原则

 

一个良好的软件系统,应该是维护起来相当容易的。Rober C.Martin曾经指出,导致一个软件系统可维护性低的根本原因在于以下四点:

1,过于僵硬

      很难在软件系统中增加新的功能,哪怕是很小的功能都很难, 这是因为加入一个新的功能,不仅仅是意味着建造一个新的模块,而且因为这个新的模块会波及其他模块,最后导致跨越多个模块的改动,使得一个最初只需要几天的工作,变成一个需要持续作战几周甚至更长时间的连续作战。由于这种缺陷,使得不敢轻易的向项目中添加新的功能,结果就是一个系统中,功能一旦完成,就不能新增功能的僵硬化情况。

2,过于脆弱

       这是和过于僵硬同时存在的,是软件在修改代码的时候过于脆弱,对一个地方的修改,往往会导致另一个或多个看上去没啥关系的地方,发生故障。

3,复用率低

        所谓的复用,就是在同一项目的不同位置甚至是不同的项目中进行代码的重复使用。当程序员发现一个方法,模块,所做的事情是在新的模块中可以使用的时候,总是发现这些已有的代码依赖于一大堆其他的东西,很难拆分。最后发现最好的办法就是不碰这些已有的东西,而是自己重新写,但是会使用复制粘贴的方式去复制部分可用的代码,以节约时间。

4,粘度过高

       有时候,一个改动可用以保存原始设计意图和原始设计框架的方式进行,也可以以破坏原始意图和框架的方式进行。第一种办法会对整个系统有利,第二种只是权益之计策,短期可用解决问题,但是会牺牲长期利益。如果第二种办法比第一种要容易很多的话,那么程序员就有可能牺牲长期利益,使用权宜之计:在模块中搭建一个桥,或者在通用的逻辑中创建一个特例,用来解决眼前的需求。如果总是使得第二种方法比第一种通用,那么就是粘度过高。

 

为了解决以上问题,有六大基本原则 

  1. “开 - 闭“原则
  2. 里氏代换原则
  3. 依赖倒转原则
  4. 接口隔离原则
  5. 组合/聚合复用原则
  6. 迪米特法则

开 - 闭原则 

     开闭原则讲的是一个软件实体,应当对扩展开放,对修改关闭。说的是在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。也就是说,应该在不比修改源代码的情况下改变这个模块的行为。满足开闭原则的系统会有两个无可比拟的优越性 :

            1. 通过扩展已有的软件系统,可以提供新的行为,以满足对软件新的需求,让变化中的软件有一定的适应性和优越性

            2. 已有的软件模块,特别重要的是抽象模块不能再次修改,这也使得变化中的软件具有一定的稳定性和延续性

     如何做到开闭原则

            在java语言中,如何做到开闭原则呢?

            抽象是关键:

            可以给系统定义出一个一劳永逸的,不用再修改的抽象设计,此设计允许有无穷无尽的行为在实现层被实现,这个抽象层预见了所有的可能性。因此,在任何扩展情况下都不会改变。这就使得系统的抽象层不需要再修改,满足了对修改关闭。同时,由于从抽象层导出了一个或多个新的具体的类改变系统行为,因此也满足了对扩展开放。

            对可变性的封装原则:

            找到一个系统的可变因素,并将它封装起来。考虑你的设计中什么可能会发生变化,与通常将焦点放到什么会导致设计改变思考方式相反,这一思考方式不是什么会导致设计发生改变,而是考虑怎样允许它发生改变而不让这一变化重新导致设计.

            (1) 一种可变不应该散落在代码的各个角落,而应当被封装在一个对象里面,同一种可变现的不同表现意味着同一继承结构中的各种具体子类,继承应该被看做是封装变化的方法,而不是应该被认为是一般对象生成特殊对象的方法

             (2)一种可变现不应该和另一种可变性混合在一起。

 

里氏代换原则

             任何父类可以出现的地方,那么它的子类也一定能够出现。一个软件实体如果使用的是一个父类,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,软件里面,把父类都替换成它的子类,程序的行为没有变化。反过来则不一定成。java中里氏代换原则能够成立的原因在于继承和多态。

             假如有一个Father类,一个Son类,他们之间是继承关系。现假设有这么一个方法

public void method(Father f) {
    // .....
}

无论是传入 Father的实例还是 传入Son 的实例, 这个方法都可以运行成功。

    反过来的代换不成立

           就java语言来说,编译器会在编译期间检测一个程序是否符合里氏代换原则,这是一个无关实现,纯语法意义上的检查。里氏代换要求凡是基类使用的地方,子类一定适用,因此子类必须实现基类的所有接口,并且子类有可能扩张父类的接口。如果破坏这一原则,那么编译器会给出编译时错误。如下面的例子

// 这是父类
public class Father {
    public void method(){
        //...
    }
}

// 这是子类

public class Son extends Father {
    
    // 这里会有一个编译时错误,里氏代换原则被破坏,无法继续编译
    @Override
    private void method() {
       //.....
    }
}

从上面的例子可以看出java是从语法上支持里氏代换原则的,客户端完全有可能调用超类的公开方法,如果子类取而代之,那么此方法变成私有,客户端无法调用,显然是违反了里氏代换原则。

依赖倒置原则    

          未完待续....

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值