问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
class Book{ public String getContent(){ return "很久很久以前有一个阿拉伯的故事……"; } } class Mother{ public void narrate(Book book){ System.out.println("妈妈开始讲故事"); System.out.println(book.getContent()); } } public class Client{ public static void main(String[] args){ Mother mother = new Mother(); mother.narrate(new Book()); } }
运行结果:
妈妈开始讲故事
很久很久以前有一个阿拉伯的故事……
public String getContent(){ return "林书豪38+7领导尼克斯击败湖人……"; } }
我们引入一个抽象的接口IReader。读物,只要是带字的都属于读物:
interface IReader{ public String getContent(); }
Mother类与接口IReader发生依赖关系,而Book和Newspaper都属于读物的范畴,他们各自都去实现IReader接口,这样就符合依赖倒置原则了,代码修改为:
class Newspaper implements IReader { public String getContent(){ return "林书豪17+9助尼克斯击败老鹰……"; } } class Book implements IReader{ public String getContent(){ return "很久很久以前有一个阿拉伯的故事……"; } } class Mother{ public void narrate(IReader reader){ System.out.println("妈妈开始讲故事"); System.out.println(reader.getContent()); } } public class Client{ public static void main(String[] args){ Mother mother = new Mother(); mother.narrate(new Book()); mother.narrate(new Newspaper()); } }
妈妈开始讲故事
很久很久以前有一个阿拉伯的故事……
妈妈开始讲故事
林书豪17+9助尼克斯击败老鹰……
在实际编程中,我们一般需要做到如下3点:
- 低层模块尽量都要有抽象类或接口,或者两者都有。
- 变量的声明类型尽量是抽象类或接口。
- 使用继承时遵循里氏替换原则。