在Java和C#的编程世界里,并没有出现像C++那样的多脉继承,它们只支持单一的继承,或者多级继承,这一变化最大的影响,我觉得是大大的降低了编程的难度,因为没有了C++的多级多脉继承,所以接口出现了,它支持多重继承,当然它的主要目的是为了实现解耦,将定义与实现分离。今天就来谈谈我对Java中面向接口编程的看法,以及个人的一些改进。
先看下面一段简短的代码,
public static void main(String[] args){loginDao dao = new loginDaoImpl();String result = dao.loginInvalidate("root", "123");System.out.println("result:" + result);}
重点是包含new的那一行,这是我刚做项目时的写法,定义一个接口,一个该接口的实现类,测试的时候,通过多态实例化接口即可。但是如此,我们不得不想,面向接口的初衷是为了将定义与实现进行分离,从而达到解耦的目的。但是如果像上面的那种方式使用,那么对于一个大型的项目,那得修改多少这样的类,工作量大的吓人,所以,我们需要重新思考面向接口的使用。针对这种情况,决定采用简单工厂模式,配合单例模式,对面向接口编程进行深度解耦。
下面我们再看一段简短的代码:
public static void main(String[] args){loginDao dao = DataFactory.createLoginDao();String result = dao.loginInvalidate("root", "123");System.out.println("result:" + result);}
这段代码和上一段代码有一个明显的差别,就是使用了DataFactory这个自定义的工厂类,下面我们来详细研究这个工厂类:DataFactory
package com.azer.shop.factory;import com.azer.shop.constant.Constants;import com.azer.shop.dao.loginDao;import com.azer.shop.utils.LoadProperty;public class DataFactory{/*** 实例化登录验证接口* * @return*/public static loginDao createLoginDao(){try{return (loginDao) Class.forName(LoadProperty.getClassName(Constants.LOGINDAOIMPL)).newInstance();} catch (Exception e){e.printStackTrace();return null;} }}
其实这段代码也很简单,就是实例化一个接口,不过并没有使用new,取而代之的是newInstance。两者的区别主要体现在newInstance是一种弱类型。低效率的方式,只能调用无参构造。而new是一种强类型。相对高效的创建对象的方式,能调用任何public构造函数。在这个方法里,我们使用反射来实例化一个对象,在Class.forName()方法的参数中只需要提供完整的类名(包名+类名),就可以实例化该类。为了进一步解耦,我们将该完整的类名写入到一个属性文件中,取出的时候根据键来获取完整的类名。进一步的改进,我们将键名写入到一个常量文件中,当以后需要修改的时候,只需要修改该常量即可,非常方便。Constants.LOGINDAOIMPL代表属性配置文件中键的名称,LoadProperty.getClassName()的目的是为了获取接口实现类的完整类名名称。
package com.azer.shop.utils;import java.io.InputStream;import java.util.Properties;import com.azer.shop.constant.Constants;@SuppressWarnings("serial")public class LoadProperty extends Properties{private static LoadProperty instance;public static LoadProperty getInstance(){if (instance != null){return instance;}else{makeInstance();return instance;}}private static synchronized void makeInstance(){if (instance == null){instance = new LoadProperty();}}private LoadProperty(){InputStream inputStream = getClass().getResourceAsStream(Constants.FILE_NAME);try{load(inputStream);} catch (Exception e){System.out.println("配置文件出错!!");e.printStackTrace();}}public static String getClassName(String classNameKey){return LoadProperty.getInstance().getProperty(classNameKey);}}
下面是完整的源码,提供给读者进行学习、交流。