六大设计原则

单一职责原则

单一职责,顾名思义,只做一件事。定义是:There should never be more than one reason for a class for change。在对类或者接口设计的时候,尽量保证一个类或者一个接口只做同一种类型的事情。

example

原有设计:

public interface UserManager {
void UserManager(UserInfo userinfo,UserAdd useradd,UserWork userWork.....)
}

改进设计:

public interface UserManager {
void changeUserName(String name....)
void changeAdd(String add.....)
void changeWork(String work.....)
}

Notice: 在单一原则设计时,可能对于职责的定义会根据业务的不同,单一原则无法确定。但是应该保证接口是单一职责,而类的设计可以尽量单一。

里氏替换原则

里氏替换原则的定义,也就是说所有可以用基类的地方,就可以用从基类继承的子类对象。

原版定义是: Functions that use pointers or references to base classes must be able to use object of derived classes without knowing it.

虽然定义是简单的,但是可以提炼出四层含义

- 子类必须完全实现父类的方法

当我们设计了接口或者抽象类的时候,都需要进行具体的实现。这里有一个原则是使接口或者抽象类作为参数。这样就能保证任意的实现自基类或者接口的子类,都可以进行调用,这是一种松耦合的设计。
子类必须完全实现父类的方法,这是肯定的。假如需要调用父类的某一个方法,然而子类没有实现,那么就必然违反了这个原则

-子类可以有自己个性

子类继承父类后,一般会有自己个性的方法或者参数。扩展了父类后,子类能出现的地方父类就不一定能出现。这是明显的。

-覆盖或实现父类方法时输入参数可以被放大

当子类override父类方法时,本着父类出现的地方子类可以出现的原则,因此要去该方法的参数应该大于等于父类的方法,这样才能被替换。

- 覆写或实现父类的方法时输出结果可以被缩小

当父类的一个方法返回类型为T,子类覆写该方法时,返回类型S,要求S类型小于等于T。还是抓住替换原则的根本去理解,就很好理解了。当父类出现的地方,如果替换成子类后,返回的类型大于父类的类型,那么就无法转换到低类型,不符合里氏替换原则。

里氏替换原则的目的:增强程序健壮性,版本升级时也能保持很好兼容性,即使增加了子类,原有的系统还能正确运行。

依赖倒置原则

这个原则大家就比较熟悉了。JAVA开发的同学都知道Spring的IoC(控制反转),和这里的依赖倒置的思想还是比较相近的。先说说书面的定义:

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

意思就是:高层模块不应该依赖于底层模块,都应该依赖于抽象。抽象不能依赖于具体实现。具体实现应依赖于抽象。这也是面向接口编程(OOD)的精髓之一。

举个栗子:
在开车驾照的设计中,我们有A照,B照,C照等等。规定是假如你持有C照(抽象类或接口),那么你就可以开手动小汽车、自动小汽车、三轮车、小货车等等(抽象的具体实现)。但是假如驾照的设计是一种类型的车就得考对应的驾照,那么有的人可能需要随时带上一堆的驾照。一个统一的C照,就可以避免了我们单独每一种类型的车都去考驾照。是不是很方便?假如以后家里买了小三轮,就不用去考一个三轮驾照,直接用C照就行了(三轮驾驶资格属于C照允许范围内),是不是很方便(方便扩展)。

也就是说,依赖倒置减少类之间的耦合性,提高了系统的稳定性,降低了并行开发的风险。因为大家依赖的是抽象,而不是具体实现,就不需要等待别人具体实现后才能开发其他模块。

这里有几点最佳实践需要注意:

  • 每个类都尽量有接口或者抽象,或都有
  • 变量的表面类型尽量是接口或在抽象类
  • 任何类都不应该从具体类派生,都应该出自抽象
  • 尽量不要覆写基类方法
  • 结合里氏替换原则

接口隔离原则

接口隔离原则,顾名思义,就是接口需要隔离。(好吧……笑话好冷……)首先我们需要明确接口的定义。大家基本都知道,以interface定义的类接口(Class interface),这只是一类接口。但是普通的类(Object interface)也是一类接口。

那我们所说的接口隔离是什么意思呢?总结来说,就是两点:1.使用者不应该依赖它不需要的接口。2.类间的依赖应该建立在最小的接口上。解释一下,就是我们在设计接口的时候,尽量细化接口,接口中的方法尽量少,使得接口的职责尽量单一。

但是接口隔离和我们上面说的单一原则有什么不同呢?接口隔离所强调的是接口本身的方法尽量少,单一原则强调的是业务的单一。

举个栗子:

假如有一个美女接口,设计如下

public interface BeautifulGirl {
    public void goodLooking();   //颜值高
    public void goodBody();   //身材瘦
    public void goodTemperament()  //气质好
}

感觉好像也没什么问题。但是假如我们现在的审美变了,身材越胖越好看(梦回唐朝)。那么我们就需要改变这个接口。身材这个部分可能单独会变化,因此我们需要拆分成两个接口。

public interface BeautifulWithBody {
 public void goodBody();   //身材瘦
}


public interface BeautifulWithOther {
 public void goodLooking();   //颜值高
 public void goodTemperament()  //气质好
}

我们在设计接口的时候,需要尽量使一个接口只服务于一个子模块或者业务逻辑,通过业务逻辑压缩接口中的public方法,缩小接口提供的服务数量。但是当接口已经很乱了,那么就采用适配器模式去转换处理。

迪米特法则

迪米特法则,也称最小知识原则。就是一个类应该对自己需要耦合或调用的类知道的越少越好。这样可以使得模块的设计松耦合。
举个栗子

public class A {
 public functionTest(ClassB B) {
     List<ClassC> listC = new ArrayList();
     ......
 }
}

这个栗子中,在类A的方法functionTest中,传入类B,同时使用类C。因此类A中就包含了类C的使用。假如类C需要改变,那么类A也需要改变,不符合我们的松耦合设计。
那我们按照最小知识原则进行一下优化:

public class A {
public functionTest(ClassB B,ClassC C) {
    List<ClassC> listC = new ArrayList();
    ......
 }
}

这样,A就不用包含C。当C变化的时候,A不用变。而且一般参数我们可以传入接口或者抽象类,这样使得耦合度更低。
但是并不是越隔离越好。我们应该遵守尽量减少public方法,尽量少暴露接口。

开闭原则

开闭原则是所有原则的核心。首先介绍什么是开闭原则。

开闭原则:对扩展开放,对修改关闭

简单理解,就是说一个软件实体(功能模块、抽象和类、方法),有新的需求,需要扩展的时候,尽量不能去修改他本身代码,应该对他进行继承扩展。
在软件的开发过程中,需求变化是时有的事情。因此我们在开发软件的过程中,需要保持软件的可扩展性,时刻准备拥抱变化。
至于怎样具体去实现开闭原则,有很多方式,比如采用抽象、接口设计,以及我们所说的23种设计模式,都是开闭原则的具体实现。
开闭原则的使用,可以使得扩展后的测试很方便,同时可以提高软件复用性、可维护性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值