软件设计的原则

软件设计的原则

单一职责原则

单一职责原则(Single responsibility principle,SRP)初看起来是个很简单的一个原则,只做一件事嘛。但是,往往越是寻常普通的事物,追究起来,越是可能蕴含非比一般的意义。

事实上,软件设计出来是要解决具体问题的,而实际生活千千万万的事物,都不是那么简单可以用单一行为来模拟抽象的。比如,一个鸟儿会鸣叫,会喝水,会飞;一个手机可以打电话、玩游戏、聊天,上网查资料等等。在实际开发如何度量、划分职责,并不是一件随随便便的事情;

SRP原话是:

There should never be more than one reason for a class to change。

一个事物具备多个行为,将多个行为分别抽象成单独的行为接口,与将事物本身抽象成接口;前者更符合设计原则,但是后者往往是实际开发的选择。因为后者看起来似乎更简单一些,尤其是时间有限,技术有限的情况下。

但是长远来看,有时候前期偷懒的行为,经常会导致后期维护困难,甚至可能会面临改一个功能需要大范围修改代码的情况。所以,更应该将单一职责作为一种标准,做开发需要细细琢磨,将其深入到日常开发中。

里式替换原则

里式替换原则(Liskov Substitution principle,LSP)包含两个含义:

  1. 在T 出现的任何地方,都可以替换成S,且不会改变程序的行为;那么,可以认为S是类型T子类型;
  2. 所有使用基类的地方,都应该可以透明地替换成其子类型;

在使用面向对象的语言进行编程时,继承是一个非常重要的一部分;它具有不少优点:

  • 可以将公共代码共享在基类,提高代码复用性
  • 子类可以继承父类的对外接口,又可以做部分定制;提升了可扩展性

同时,它也具有一些缺点:

  • 继承有一定的侵入性,派生类拥有基类的方法,且可以覆盖基类定义的行为;
  • 在一定程度上,基类的存在就影响到了派生类的灵活性;
  • 继承在某种程度上,增强了耦合性;派生类修改基类的属性或行为时,有可能会带来不好的结果;

比如,如果对于Phone这个基类,除了派生出在严肃场景下,可以正常使用的IPhone、Andrond、老式功能机等子类;也可以定义出小孩子的玩具手机,破坏原有的功能,比如通话聊天;

里式替换原则相当于做了一个规范,来约束继承的泛滥;

  1. 子类必须完全实现父类的方法,使用父类的地方,就可以使用子类;
  2. 子类可以有自己的特殊性;使用子类的地方,不需要可以替换成父类;
  3. 覆盖和实现父类的方法时,输入参数可以被放大;
  4. 复写或实现父类的方法时,输出结果可以被缩小;
依赖倒置原则

依赖倒置原则 (Dependence Inversion Principle,DIP)包含三个含义:

  1. 高层模块不应该依赖底层模块,两者都应该依赖抽象;
  2. 抽象不应该依赖细节
  3. 细节应该依赖抽象

这个比较好理解,尤其是现在Java项目基本都使用Spring开发,通过Ioc机制,基本都是面向接口的编程;

依赖倒置的三种实现方式:

  1. 通过构造函数
  2. 通过setter
  3. 通过接口方法声明
接口隔离原则

这里的接口不单单指的是Java中interface关键字声明的接口,也包括实例接口。对一个对象来说,它对应的类就是实例接口。接口隔离原则有两个定义:

  1. 客户端不应该依赖它不需要的接口上
  2. 类间的依赖关系应该建立在最小的接口上

依据这个职责,应该尽量细化接口,接口中的方法应该尽可能的少。

参照《设计模式之禅》,接口隔离的最佳实现:

  • 一个接口应该只服务于一个子模块或者业务逻辑
  • 接口不应该暴露过多的public方法
  • 已经污染的接口,尽量修改;若变更风险较大,可以考虑适配器模式转化处理
  • 了解环境,拒绝盲从;针对实际业务背景进行拆分,不要照搬照抄
迪米特法则(最少知识原则)

比较好记的还是最少知识原则,即一个类应该对它的依赖保持最少的了解,尽量降低类之间的耦合;

对于迪米特法则,有以下几点需要注意:

  1. 只和朋友交流,类不应该去了解依赖背后做的事情,而跟依赖对象依赖的第三方有交集
  2. 朋友之间也应该保持距离;尽可能约束类的对外、对子类的方法和属性;需要在访问权限上尽可能收窄
  3. 是自己的就是自己的;如果出现一个方法不知道放在哪个类中,那么可以这样考虑:如果一个方法放在本类中,既不增加类间关系,也不对类产生负面影响,那就可以放置在本类中
开闭原则

简单来说,就是对扩展开放,对修改关闭;理解起来就是,尽量不修改源码,依然可以增加新功能;

原文:

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

开闭原则,指出当出现新的需求时,应该首先考虑通过扩展现有的接口,而不是修改现有的代码。对一个接口来说,如果在当前接口上新增一个方法表示新的行为的话,会导致所有现有的实现都跟着变。应当首先考虑扩展,比如创建继承老接口的新接口,新的行为只需要在新的实现类中添加’。

软件不是开发出来就可以一直保持不变,而是往往会发生变化。开闭原则也指导我们,要拥抱变化,在软件的设计之处,可以考虑下以后可能的变化,并为之提供便利。


以上是六大设计原则,但是有的书还会提到另外一个原则,合成复用原则;

合成复用原则

合成复用原则,尽量使用对象组合或对象聚合的方式来实现代码复用,而不是继承关系;这个也比较好了理解,也就是大家常说的,组合优于继承;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值