我们都知道修改是无法避免的,我们能做的是,尽量降低修改的影响面。
设计模式的核心之一就是:把可能变化的点收敛到一起,降低修改的影响面。
面向接口编程和工厂模式搭配使用,目的就是降低变量类型修改的影响面,把变量类型的修改收敛到工厂类中。
面向接口编程:
Map<String, Integer> map;
和面向实现编程:
Hashtable<String, Integer> map;
唯一的区别就是,声明为接口类型的变量可以对应接口的任意一个实现,而面向实现编程就被限定死了依赖一个具体的实现。如果要替换实现就不得不修改所有相关变量的声明。
变量声明为接口类型后,在使用前总归需要一个具体的实现。如果这样写:
Map<String, Integer> map = new ConcurrentHashMap<>();
那还是依赖了具体的实现。
所以这个时候就需要工厂模式了(或其他创建型模式),
Map<String, Integer> map = Factory.createMap("concurrentMap");
工厂模式的具体实现可以是:
public class Factory {
public static<K, V> Map<K, V> createMap(String name) {
switch (name) {
case "map":
return new HashMap<>();
case "sortedMap":
case "navigableMap":
return new TreeMap<>();
case "concurrentMap":
return new ConcurrentHashMap<>();
default:
return new ConcurrentHashMap<>();
}
}
}
此时如果需要替换concurrentMap的实现,只需要修改工厂方法即可。concurrentMap的所有使用方无感知,不需要修改。
这个图可以很好的表达本文所描述的内容:
假设类D、E是可能变化的点,未来可能会换成类F、类G啥的。
面向接口编程和工厂模式,把类A、B、C对类D、E的多对多依赖,转换为工厂类对类D、E的一对多依赖。类D、E的变化只会影响工厂类,而不会影响类A、B、C。
工厂模式相当于加了一个中间层,把多对多的依赖关系简化为多对一和一对多的依赖,像这样搞的设计模式不止工厂模式一个,贴两个图大家感受一下。
外观模式(门面模式):

防腐层设计模式:

网友评论