在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);
}
}
下面是完整的源码,提供给读者进行学习、交流。