在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);
	}
}



下面是完整的源码,提供给读者进行学习、交流。