面向接口编程
-
概念:接口是一种特殊的抽象类,与一般抽象类相比,接口中的所有方法都是抽象方法,所有属性都是常量。
-
接口通常用来定义实现类的外观,也就是实现类的行为定义,用来约束实现类的行为
-
接口的思想:封装隔离。隔离外部调用与内部实现,外部调用只能通过接口调用,不知道内部具体实现
-
接口还是抽象类:
-
优先使用接口
-
在既要定义子类的行为,又要为子类提供公共的功能时应选择抽象类
-
/** *@Function: 接口(通用的、抽象的、非具体的功能) *@Author: hxq *@Date: 2014-6-18 */ public interface Api { public void operation(String s); } /** *@Function: 对接口的实现 */ public class Impl implements Api{ @Override public void operation(String s) { System.out.println(s); } } /** *@Function: 客户端:未使用模式 */ public class Client { public static void main(String[] args) { /** * 接口的思想是封装隔离,实现类Impl应该是被接口Api封装并同客户端隔离的 * 客户端不应该知道具体的实现类是Impl */ Api api=new Impl(); api.operation("没有模式"); } }
把这个问题描述一下:java编程中,只知道接口而不知实现,怎么办?一个合理的解决方案就是简单工厂
简单工厂(静态工厂方法模式)
定义:
提供一个创建对象实例的功能,而无须关心其具体实现。被创建实例的类型可以是接口、抽象类,也可以是具体类
结构:
-
工厂类:工厂,选择合适的实现类来创建Api接口对象
-
抽象产品:定义客户需要的功能接口(Api)
-
具体产品:Api的具体实现类
/** *@Function: 简单工厂 */ public class Factory { public static Api createApi(){ return new Impl(); } } /** *@Function: 客户端:简单工厂 */ public class Client { public static void main(String[] args) { Api api=Factory.createApi(); api.operation("简单工厂 ^_^ "); } }
可配置简单工厂
在现在的实现中,再新增一种实现,该怎么办呢?那就需要修改工厂类,把新的实现添加到现有系统中。类似下面这样:
public class Factory { public static Api createApi(int type){ Api api=null; if(type==1){ api=new Impl(); }else{ api=new Impl2(); } return api; } }
如果每增加一个实现类都来修改工厂类的实现,肯定不是一个好的实现方式。对此,一种解决方式就是使用配置文件(通常是xml,也可以properties文件)。当有了新的实现类,只要在配置文件中配置即可。在简单工厂的方法中可以使用反射,也可以使用IOC/DI(控制反转/依赖注入)来实现。
简单工厂的优缺点:
-
优点
- 帮助封装:实现了组件的封装,让组件的外部能真正的面向接口编程
- 解耦:实现客户端与具体实现类的解耦
-
缺点
-
可能增加客户端的复杂度:如果通过客户端参数来选择实现类,就必须让客户端理解各个参数代表的具体功能与含义,增加使用难度,也暴露部分实现
-
不方便扩展子工厂:私有化简单工厂构造方法,使用静态方法创建接口,就不能通过写简单工厂类的子类来改变创建接口的方法的行为。当然通常也不需要这么做
-
简单工厂的本质
简单工厂的本质是:选择实现
注意简单工厂的重点在选择,实现是已经做好了的。就算实现再简单,也要由具体的实现类来实现,而不是在简单工厂里面实现。简单工厂的目的在于为客户端选择相应的实现,从而使得客户端与实现解耦。这样一来,具体实现发生了变化,就不用变动客户端了,这个变化会被简单工厂吸收和屏蔽掉。
简单工厂的本质是选择实现,所以它可以跟其他任何能具体创建对象实例的模式配合使用,比如:单例模式、原型模式、生成器模式等