1. 单一职责原则
当对实现多种功能的对象进行修改了,可能牵一发而动全身。因此最好对象只做一件事,便于代码维护和拓展。
此举能够降低类的复杂度,一个类负责一件事,便于代码维护。
优点
- 代码的粒度降低了,类的复杂度降低了。
- 可读性提高了,每个类的职责都很明确,可读性自然更好。
- 可维护性提高了,可读性提高了,一旦出现 bug ,自然更容易找到他问题所在。
- 改动代码所消耗的资源降低了,更改的风险也降低了。
2. 开闭原则
软件更新应该对扩展开放,对修改关闭。
在软件的生命周期内,因为变化,升级和维护等原因需要对软件原有代码进行修改,可能会给旧代码引入错误,也有可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。
优点
-
尽量通过扩展软件实体的行为来实现变化
-
不需要对功能重构,直接在上方建房子
-
不会引发原有功能产生bug
**用抽象构建架构,用实现扩展细节 。**因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保证架构的稳定。当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了,当然前提是抽象要合理,要对需求的变更有前瞻性和预见性。
3. 里氏替换原则
所有父类存在的场景均能用子类代替
里氏替换指所有基类都存在的地方,都可以换成子类。此举与继承有关,那么先讲下继承的优缺点。
继承的优点:
- 子类拥有父类的所有方法和属性,从而可以减少创建类的工作量。
- 提高了代码的重用性。
- 提高了代码的扩展性,子类不但拥有了父类的所有功能,还可以添加自己的功能。
继承的缺点:
-
继承是侵入性的,只要继承,子类就必须拥有父类的属性和方法。
-
降低了代码的灵活性,父类对子类有一种约束。
-
增强了耦合性,修改父类代码时必须考虑到对子类的影响
- 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
public class human
{
void walk()
{
cout << "人会走路" << end; // 人的特征
}
};
public class Asia : public human
{
void walk()
{
// 修改了人的特征,那么子类就不是人了,因此不能重写 父类 已实现的方法
cout << "人会飞" << end;
}
}
-
子类中可以增加自己特有的方法。
-
当子类重载或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松
public class human
{
void eat(Food food) // 传入的是食物
{
cout << "吃食物的是人" << end; // 人的特征
}
};
public class Asia : public human
{
void eat(vegetables ve) // 传入的是蔬菜,蔬菜是食物的子类
{
cout << "吃蔬菜的是亚洲人" << end;
}
}
public class cly
{
public static void main(String[] args)
{
// 蔬菜是食物,因此传入蔬菜时我希望得到结果为人
Asia asia = new Asia();
vegetables v = new vegetables();
asia.eat(v). // 输出吃蔬菜的是亚洲人,错误
}
}
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。若在继承时,子类的方法返回值类型范围比父类的方法返回值类型范围大,在子类重写该方法时编译器会报错。(java语法)
4. 迪米特原则
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。如果两个实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。
优点
-
降低了类之间的耦合度,提高了模块的相对独立性。
-
由于亲合度降低,从而提高了类的可复用率和系统的扩展性。
缺点
- 过度使用会造成系统产生大量的中介类,从而增加系统的复杂度
实现方法
-
从依赖者的角度来说,只依赖应该依赖的对象。 // 我只需要必要的资源,其他资源与我无关
-
从被依赖者的角度说,只暴露应该暴露的方法。 // 我提供你要的资源,其他资源与你无关
5. 接口隔离原则
5.1 介绍
- 客户端不应该依赖它不需要的接口
- 类间的依赖关系应该建立在最小的接口上
- 要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
5.2 优缺点
- 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
- 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。
- 如果接口的粒度大小定义合理,能够保证系统的稳定性;但是,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险。
- 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。
- 能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。
5.3 实现方法
- 根据接口隔离原则拆分接口时,首先必须满足单一职责原则。
- 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
- 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
- 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同,应该深入了解业务逻辑。
- 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
6. 依赖倒置原则
6.1 定义
上层模块不应该依赖底层模块,它们都应该依赖于抽象
抽象不应该依赖于细节,细节应该依赖于抽象
6.2 描述
将具体细节抽象化,形成细节依赖抽象,且上层模块也依赖抽象
6.3 优点
降低模块之间的耦合,同时便于功能的扩展
7. 合成复用原则
指在一个对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分。新对象通过委派调用已有对象的方法达到复用其已有功能的目的。尽量少用继承。