SRP: Single Responsibility Principle

  • 浅显的解释是软件模块只提供单一功能

  • 更进一步任何一个软件模块都应该有且只有一个被修改的原因

  • 再更进一步这个原则是关于人(Actor)的

    任何一个软件模块都应该只对一个用户或系统利益相关者负责。

  • 最终就是任何一个软件模块都应该只对某一类行为负责

OCP:Open/Closed Principle

设计良好的软件应该易于扩展,同时抗拒修改。也就是说一个软件模块应该允许在不修改源码的情况下扩展它的行为。

可以通过组合 SRP(代码分组)和调整依赖关系实现(DIP)。如果 A 组件不想被 B 组件上发生的修改所影响,那么就应该让 B 组件依赖于 A 组件。

LSP:Liskov Substitution Principle

里氏替换原则:多态。

每个类型是 S 的对象 o1 都存在一个类型为 T 的对象 o2,能使操作 T 类型的程序 P 在用 o2 替换 o1 时行为保持不变,我们就可以将 S 称为 T 的子类型。

public class LiskovSub {
	public static main(String[] args) {
		T o1 = new S();
		T o2 = new T();

		P(o1); // ok
		P(o2); // ok
	}

	public static P(T o) {
		o.doSomeThing();
	}
}

正长方形问题

public class NonLiskovSub {
	public static main(String[] args) {
		Rectangle r = new Sqaure();
		r.setW(5);
		r.setH(2);

		assert(r.area() == 10); // 不成立
	}

	public static class Reactangle {
		private int w = 0;
		private int h = 0;

		public void setW(int w) {
			this.w = w;
		}

		public void setH(int h) {
			this.h = h;
		}

		public int area() {
			return w * h;
		}
	}

	public static class Square extends Rectangle {
		@Override
		public void setW(int w) {
			setSide(w);
		}

		@Override
		public void setH(int h) {
			setSide(h);
		}

		public void setSide(int s) {
			this.w = s;
			this.h = s;
		}
	}
}

ISP: Interface-Segregation Principle

用户应该不依赖它不是用的方法。臃肿的方法拆分成更小更具体的角色接口。

DIP: Dependency Inversion Principle

如果想要设计一个灵活的系统,在源代码层面的依赖关系中就应该多引用抽象类行,而非具体实现。

这一原则不针对已经稳定不变的部分,而是针对那些经常 变动的(volatile) 模块。

  • 应在代码中多使用抽象接口,尽量避免使用那些多变的具体实现类 。同时应使用抽象工厂严格限制对象的创建过程。
  • 不要再具体实现类上创建衍生类 。静态语言中继承依赖最强且最难被修改。
  • 不要覆盖(override)包含具体实现的函数 。通过创建一个抽象函数,然后再为该函数提供多种具体实现。
  • 应避免在代码中写入与任何具体实现相关的名字,或者是其他容易变动的事物的名字

工厂模式之于非常重要。