开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情
面向接口编程
- 每个模块负责自己的职责(
单一职责原则),各个模块之间通过接口通信。 - 每个模块对应该承诺,自己对外暴露的接口是不变的,当模块内部底层实现发生变化,其他模块是不需要知道的。这便是依赖抽象,而不是依赖实现(
依赖倒置原则)。 - 上层模块只需要知道下层暴露的接口即可,如何实现无需关心 (
迪米特法则)。
相关概念
-
产品: 类
-
抽象产品: 抽象类/接口
-
产品簇: 多个有内在联系或者有逻辑关系的产品
-
产品等级:
代码演示
-
A
-
代码
//抽象产品 interface Food{ void eat(); } //具体产品 class Hamburger implements Food{ @Override public void eat() { System.out.println("吃汉堡包!"); } } public class AppTest { public static void main(String[] args) { Food food = new Hamburger(); food.eat(); } } -
分析
- 这种设计很脆弱,比如当具体产品的类名
Hamburger发生修改,用户中new Hamburger也需要一起改变 - 这样,具体产品和用户的代码是耦合的
- 我们希望具体产品如何修改,用户也应该是不知道的。也就是需要解耦。
- 这种设计很脆弱,比如当具体产品的类名
-
-
B
-
针对于A中的问题,我们进行如下改进。使用简单工厂设计模式。
-
代码
//抽象产品 食物 interface Food{ void eat(); } //具体产品 汉堡包 class Hamburger implements Food{ @Override public void eat() { System.out.println("吃汉堡包!"); } } //具体产品 米线 class RiceNoodle implements Food{ @Override public void eat() { System.out.println("吃米线"); } } //食物工厂 class FoodFactory{ //获取食物 public static Food getFood(int type){ Food food = null; switch (type){ case 1 : food = new Hamburger(); break; case 2 : food = new RiceNoodle(); break; } return food; } } //测试 public class AppTest { public static void main(String[] args) { FoodFactory.getFood(1).eat(); FoodFactory.getFood(2).eat(); } } -
分析
-
优点
- 具体产品和用户解耦。
- 当具体产品的类名发生修改,客户无需知道。继续调用食物工厂的方法即可获取对应的对象。
- 符合了面向接口编程(非字面意思)的思想
-
缺点
- 用户需要记住 数字与具体产品的映射关系。 1 -》 汉堡包 2-》米线
- 当用户需要扩展具体产品,则需要修改食物工厂中的代码,违反了
开闭原则
-
-
-
C
- 针对于B中的问题,我们使用
工厂方法模式进行改进 具体看模块-02-工厂方法模式即可。
- 针对于B中的问题,我们使用