对于刚刚接触Java的人来讲经常的一个疑问就是“接口与抽象类有何不同?”,为了回答这个问题,我们可以从一个扩展Spring Controller的例子来看看接口与抽象类的不同及如何将其使用在OO设计中。
需求的场景是这样的:扩展Controller实现返回Json数据格式的Ajax的Controller,对于继承后的子类只需实现返回要序列化为Json数据格式的对象,而无需关注如何返回Json数据。
实现了需求场景的实例:
基本接口定义,定义返回Json数据格式的方法。扩展的抽象类需实现此方法。
Java代码
public interface JsonProvider {
abstract void pushJsonResponse(HttpServletResponse response, Object obj) throws IOException;
}
public interface JsonProvider {
abstract void pushJsonResponse(HttpServletResponse response, Object obj) throws IOException;
}
实现了接口的抽象类,此类实现了接口中定义的pushJsonResponse()方法,并加入了新定义的抽象方法handleJsonRequest(),供子类实现
Java代码
/**
* Description:<br>
* Origin Time: 2009-6-12 上午11:07:18<br>
*
* @author Seraph<br>
* @email:seraph115@gmail.com<br>
*/
public abstract class JsonProviderController extends AbstractController
implements JsonProvider {
private static final Log log = LogFactory
.getLog(JsonProviderController.class);
public void pushJsonResponse(HttpServletResponse response, Object obj)
throws IOException {
if (obj == null) {
obj = new Object();
log.warn("obj is null");
}
ResponseUtils.setJsonHeader(response);
PrintWriter out = response.getWriter();
out.print(JsonUtils.toJson(obj));
out.close();
}
protected abstract Object handleJsonRequest(HttpServletRequest request,
HttpServletResponse response);
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
Object obj = handleJsonRequest(request, response);
pushJsonResponse(response, obj);
return null;
}
}
/**
* Description:<br>
* Origin Time: 2009-6-12 上午11:07:18<br>
*
* @author Seraph<br>
* @email:seraph115@gmail.com<br>
*/
public abstract class JsonProviderController extends AbstractController
implements JsonProvider {
private static final Log log = LogFactory
.getLog(JsonProviderController.class);
public void pushJsonResponse(HttpServletResponse response, Object obj)
throws IOException {
if (obj == null) {
obj = new Object();
log.warn("obj is null");
}
ResponseUtils.setJsonHeader(response);
PrintWriter out = response.getWriter();
out.print(JsonUtils.toJson(obj));
out.close();
}
protected abstract Object handleJsonRequest(HttpServletRequest request,
HttpServletResponse response);
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
Object obj = handleJsonRequest(request, response);
pushJsonResponse(response, obj);
return null;
}
}
继承后的子类,享用了抽象类实现的接口方法,自己只需要实现抽象类中的抽象方法,返回要Json序列化的对象即可
Java代码
/**
* 类说明:<br>
* 创建时间: 2008-8-15 上午11:07:55<br>
*
* @author Seraph<br>
* @email: seraph115@gmail.com<br>
*/
public class AsyncMenuProviderController extends JsonProviderController {
private TreeManager treeManager;
public void setTreeManager(TreeManager treeManager) {
this.treeManager = treeManager;
}
@Override
protected Object handleJsonRequest(HttpServletRequest request,
HttpServletResponse response) {
String rootId = request.getParameter("id");
List<AsyncTreeNode> result = new ArrayList<AsyncTreeNode>();
List<AsyncTreeNode> list = treeManager.getLowerTreeNodeByRole(rootId);
if (null != list) {
result = list;
}
return result;
}
}
/**
* 类说明:<br>
* 创建时间: 2008-8-15 上午11:07:55<br>
*
* @author Seraph<br>
* @email: seraph115@gmail.com<br>
*/
public class AsyncMenuProviderController extends JsonProviderController {
private TreeManager treeManager;
public void setTreeManager(TreeManager treeManager) {
this.treeManager = treeManager;
}
@Override
protected Object handleJsonRequest(HttpServletRequest request,
HttpServletResponse response) {
String rootId = request.getParameter("id");
List<AsyncTreeNode> result = new ArrayList<AsyncTreeNode>();
List<AsyncTreeNode> list = treeManager.getLowerTreeNodeByRole(rootId);
if (null != list) {
result = list;
}
return result;
}
}
此例同时使用了接口和抽象类,完成了扩展自SpringController得JsonProviderController,便于让继承后的子类完成返回Json数据格式的能力。其中在抽象类中实现了繁琐的返回Json数据格式的方法,让后续的子类大大简化了代码,甚至感觉不到与普通的Controller有何不同。
接口定义了统一的行为,对于此行为可以有多种实现,而实现接口的抽象类完成了绝大部分的工作,把脏活和累活都一个人承担了下来,留给子类一个需实现的抽象方法来调用。
让我们回过头来看看刚才的问题,即“接口与抽象类的不同”:
从此例中我们可以看出接口完成的是定义统一的行为,同时也是对所实现类的一种归类和约束,告诉了我们实现此接口的类都具有相同的特性,应归为一类,在很多应用设计中我们使用空定义的接口来划分类的规属及关系,接口补充了Java的多继承能力而又不会导致象C++中由多继承引发的程序复杂化问题;
而抽象类即可以实现方法又可以定义抽象方法,抽象类可以替子类实现部分功能,把其中变化的部分交给子类来完成,具体是可以把子类共有的代码放入抽象类中完成,此复用可以大大简化代码量及其利用率。
所以接口就像是本儿武当派的秘籍,是种规范,规定你如何去打,如何运用此门武功。而抽象类更像是你武当派的师傅,他教你怎样打,并告诉徒弟们应该有创新,应该有自己的招式,这样在他的指导下你就进步了,学会了本来不会的武功,并专注于研究你自己的招式。
对于OO设计中如何使用接口及方法的深刻理解还需我们在实际使用中体会其美妙之处,好的设计使代码简洁易懂,易于维护和扩展,在日积月累也不会变的腐臭不堪,会长久的保持其简单的复杂度。基本的设计原则就是类的单一职能,允许扩展但不容更改。所以很多经验是积累的结果,要善于总结和钻研,所以有时偏执的完美主义者才能成功。作为软件开发者完美主义能让你成长的更快。
需求的场景是这样的:扩展Controller实现返回Json数据格式的Ajax的Controller,对于继承后的子类只需实现返回要序列化为Json数据格式的对象,而无需关注如何返回Json数据。
实现了需求场景的实例:
基本接口定义,定义返回Json数据格式的方法。扩展的抽象类需实现此方法。
Java代码
public interface JsonProvider {
abstract void pushJsonResponse(HttpServletResponse response, Object obj) throws IOException;
}
public interface JsonProvider {
abstract void pushJsonResponse(HttpServletResponse response, Object obj) throws IOException;
}
实现了接口的抽象类,此类实现了接口中定义的pushJsonResponse()方法,并加入了新定义的抽象方法handleJsonRequest(),供子类实现
Java代码
/**
* Description:<br>
* Origin Time: 2009-6-12 上午11:07:18<br>
*
* @author Seraph<br>
* @email:seraph115@gmail.com<br>
*/
public abstract class JsonProviderController extends AbstractController
implements JsonProvider {
private static final Log log = LogFactory
.getLog(JsonProviderController.class);
public void pushJsonResponse(HttpServletResponse response, Object obj)
throws IOException {
if (obj == null) {
obj = new Object();
log.warn("obj is null");
}
ResponseUtils.setJsonHeader(response);
PrintWriter out = response.getWriter();
out.print(JsonUtils.toJson(obj));
out.close();
}
protected abstract Object handleJsonRequest(HttpServletRequest request,
HttpServletResponse response);
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
Object obj = handleJsonRequest(request, response);
pushJsonResponse(response, obj);
return null;
}
}
/**
* Description:<br>
* Origin Time: 2009-6-12 上午11:07:18<br>
*
* @author Seraph<br>
* @email:seraph115@gmail.com<br>
*/
public abstract class JsonProviderController extends AbstractController
implements JsonProvider {
private static final Log log = LogFactory
.getLog(JsonProviderController.class);
public void pushJsonResponse(HttpServletResponse response, Object obj)
throws IOException {
if (obj == null) {
obj = new Object();
log.warn("obj is null");
}
ResponseUtils.setJsonHeader(response);
PrintWriter out = response.getWriter();
out.print(JsonUtils.toJson(obj));
out.close();
}
protected abstract Object handleJsonRequest(HttpServletRequest request,
HttpServletResponse response);
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
Object obj = handleJsonRequest(request, response);
pushJsonResponse(response, obj);
return null;
}
}
继承后的子类,享用了抽象类实现的接口方法,自己只需要实现抽象类中的抽象方法,返回要Json序列化的对象即可
Java代码
/**
* 类说明:<br>
* 创建时间: 2008-8-15 上午11:07:55<br>
*
* @author Seraph<br>
* @email: seraph115@gmail.com<br>
*/
public class AsyncMenuProviderController extends JsonProviderController {
private TreeManager treeManager;
public void setTreeManager(TreeManager treeManager) {
this.treeManager = treeManager;
}
@Override
protected Object handleJsonRequest(HttpServletRequest request,
HttpServletResponse response) {
String rootId = request.getParameter("id");
List<AsyncTreeNode> result = new ArrayList<AsyncTreeNode>();
List<AsyncTreeNode> list = treeManager.getLowerTreeNodeByRole(rootId);
if (null != list) {
result = list;
}
return result;
}
}
/**
* 类说明:<br>
* 创建时间: 2008-8-15 上午11:07:55<br>
*
* @author Seraph<br>
* @email: seraph115@gmail.com<br>
*/
public class AsyncMenuProviderController extends JsonProviderController {
private TreeManager treeManager;
public void setTreeManager(TreeManager treeManager) {
this.treeManager = treeManager;
}
@Override
protected Object handleJsonRequest(HttpServletRequest request,
HttpServletResponse response) {
String rootId = request.getParameter("id");
List<AsyncTreeNode> result = new ArrayList<AsyncTreeNode>();
List<AsyncTreeNode> list = treeManager.getLowerTreeNodeByRole(rootId);
if (null != list) {
result = list;
}
return result;
}
}
此例同时使用了接口和抽象类,完成了扩展自SpringController得JsonProviderController,便于让继承后的子类完成返回Json数据格式的能力。其中在抽象类中实现了繁琐的返回Json数据格式的方法,让后续的子类大大简化了代码,甚至感觉不到与普通的Controller有何不同。
接口定义了统一的行为,对于此行为可以有多种实现,而实现接口的抽象类完成了绝大部分的工作,把脏活和累活都一个人承担了下来,留给子类一个需实现的抽象方法来调用。
让我们回过头来看看刚才的问题,即“接口与抽象类的不同”:
从此例中我们可以看出接口完成的是定义统一的行为,同时也是对所实现类的一种归类和约束,告诉了我们实现此接口的类都具有相同的特性,应归为一类,在很多应用设计中我们使用空定义的接口来划分类的规属及关系,接口补充了Java的多继承能力而又不会导致象C++中由多继承引发的程序复杂化问题;
而抽象类即可以实现方法又可以定义抽象方法,抽象类可以替子类实现部分功能,把其中变化的部分交给子类来完成,具体是可以把子类共有的代码放入抽象类中完成,此复用可以大大简化代码量及其利用率。
所以接口就像是本儿武当派的秘籍,是种规范,规定你如何去打,如何运用此门武功。而抽象类更像是你武当派的师傅,他教你怎样打,并告诉徒弟们应该有创新,应该有自己的招式,这样在他的指导下你就进步了,学会了本来不会的武功,并专注于研究你自己的招式。
对于OO设计中如何使用接口及方法的深刻理解还需我们在实际使用中体会其美妙之处,好的设计使代码简洁易懂,易于维护和扩展,在日积月累也不会变的腐臭不堪,会长久的保持其简单的复杂度。基本的设计原则就是类的单一职能,允许扩展但不容更改。所以很多经验是积累的结果,要善于总结和钻研,所以有时偏执的完美主义者才能成功。作为软件开发者完美主义能让你成长的更快。