那就再进一步:面向接口编程
面向接口编程前面已经提到,接口体现的是一种规范和实现分离的设计哲学,充分利用接口可以极好地降低程序各模块之间的耦合,从而提高系统的可扩展性和可维护性。
基于这种原则,很多软件架构设计理论都倡导“面向接口”编程,而不是面向实现类编程,希望通过面向接口编程来降低程序的耦合。怪不得公司接口是先写接口再写实现。
下面介绍两种常用场景来示范面向接口编程的优势。
1.简单工厂模式
有一个场景:假设程序中有个A类需要组合一个输出设备,现在有两个选择:直接让A类组合一个B类,或者让A类组合一个接口C(B类实现这个接口C),那么到底采用哪种方式更好呢?
开设A类要给很多地方使用,定义A类推荐使用A类组合接口C,然后写一个工厂类Fac,工厂类实现接口C并重写接口C中的方法,生成B类的对象,这样A类里面就可以使用B类对象。如果B类有改动,就不用去该A类了,只需要改有改动的B类和修改工厂类的获取B类对象的方法即可。不需要动A类。就是就是将A类和经常变化的B类通过工厂类隔离开了。
2.命令模式(场景有点怪,但是其实lambda表达式已经表现出来):
考虑这样一种场景:
某个方法需要完成某一个行为,但这个行为 的具体实现无法确定,必须等到执行该方法时才可以确定。具体一 点:假设有个方法需要遍历某个数组的数组元素,但无法确定在遍历数组元素时如何处理这些元素,需要在调用该方法时指定具体的处理行为。
这个要求看起来有点奇怪:这个方法不仅需要普通数据可以变化,甚至还有方法执行体也需要变化,难道需要把“处理行为”作为一个参数传入该方法?先了解在某些编程语言(如Ruby等)中,确实允许传入一个代码块作为参数。通过Java 8引入的Lambda表达式也可传入代码块作为参数。
对于这样一个需求,必须把“处理行为”作为参数传入该方法,这个“处理行为”用编程来实现就是一段代码。那如何把这段代码传入该方法呢?
可以考虑使用一个Command接口来定义一个方法,用这个方法来封装“处理行为”。
但这个方法没有方法体—因为现在还无法确定这个处理行为。下面是需要处理数组的处理类,在这个处理类中包含一个process()方法,这个方法无法确定处理数组的处理行为,所以定义该 方法时使用了一个Command参数,这个Command参数负责对数组的处理行为。图片来自网络