在典型SSM/框架中,我們以一個處理實體對象的查詢操作流程為例。
首先表現(xiàn)層的調(diào)用業(yè)務(wù)層,對于來說,它只知道業(yè)務(wù)層公開的是這個接口所定義的方法標(biāo)準(zhǔn),而不知道接口的具體實現(xiàn)。
同理,業(yè)務(wù)層接口只知道數(shù)據(jù)持久層公開接口的方法標(biāo)準(zhǔn),而不知道接口的具體實現(xiàn)。
備注:框架只是+的一個超集框架,額外的封裝層是自動配置類的相關(guān)jar包+常用的第三方工具包
這就是所謂三層架構(gòu)中,每層對象保持較大程度的獨立性,盡可能地減少不同層之間的對象調(diào)用的依賴程度,即對象之間的解耦合。同時這種面向接口編程的風(fēng)格數(shù)據(jù)接口業(yè)務(wù)邏輯圖,也叫接口模式或(接口隔離),前一層只需知道它調(diào)用下一層所公開的接口方法標(biāo)準(zhǔn)而不用關(guān)系其他層的細(xì)節(jié),而前一層的對象往往持有下一層的接口對象的引用。
業(yè)務(wù)層代碼接口的泛型化
在展開話題之前,下面是沒有使用泛型之前的原始代碼
package com.yn.service;
import com.yn.model.Department;
public interface IDepartmentService{
/**
* 查詢所有信息
*/
public List<Department> getAll() throws ServiceException;
/**
* 條件查詢
*/
public List<Department> getByCondition(Department t) throws ServiceException;
/**
*返回總行數(shù)
*/
public int getTotal() throws ServiceException;
/**
* 批量刪除
*/
public void remove(List<Integer> ids) throws ServiceException;
/**
* 批量新增
*/
public void insert(List<Department> ts) throws ServiceException;
/**
* 批量跟新
*/
public void update(List<Department> ts) throws ServiceException;
}
l是接口的實現(xiàn)類,
package com.yn.service.impl;
import com.yn.exception.ServiceException;
import com.yn.model.Department;
import com.yn.service.IDepartmentService;
import com.yn.utils.StringUtils;
import org.springframework.stereotype.Service;
@Service("departmentServiceImpl")
public class DepartmentServiceImpl implements IDepartmentService {
private boolean checkDept(Department dept) throws ServiceException {
if(dept.getName().isEmpty()){
throw new ServiceException("部門名稱為空");
}else if(StringUtils.isSpecChar(dept.getName())){
throw new ServiceException("部門名稱不能包含特殊字符");
}else if(dept.getPhone().isEmpty()){
throw new ServiceException("電話號碼不能為空");
}else if(!StringUtils.isPhone(dept.getPhone())){
throw new ServiceException("電話號碼格式不正確");
}else {
return true;
}
}
@Autowired
private DepartmentDao dao;
/**
* 驗證部門信息的合法性
*/
abstract protected boolean checkDept(Department dept) throws ServiceException;
/**
* 查詢所有部門
*/
@Override
public List<Department> getAll() throws ServiceException {
try {
return dao.findAll();
} catch (DataAccessException e) {
throw new MyExceptionHandler().process(e);
}
}
/**
* 條件查詢部門信息
*/
@Override
public List<Department> getByCondition(Department t) throws ServiceException {
try{
return dao.findByCondition(t);
}catch(DataAccessException e){
throw new MyExceptionHandler().process(e);
}
}
/**
* 查詢所有記錄數(shù)
*/
public int getTotal() throws ServiceException{
try{
return dao.total();
}catch(DataAccessException e){
throw new MyExceptionHandler().process(e);
}
}
@Override
public void remove(List<Integer> ids) throws ServiceException{
try{
dao.delete(ids);
}catch (DataAccessException e){
throw new MyExceptionHandler().process(e);
}
}
/**
* 新增部門
*/
@Override
public void insert(List<Department> ts) throws ServiceException {
try {
Department t = ts.get(0);
if(checkDept(t)) {
dao.save(t);
}
}catch (DataAccessException e){
throw new MyExceptionHandler().process(e);
}catch(ServiceException e){
throw e;
}
}
/**
* 更新部門
*/
@Override
public void update(List<Department> ts) throws ServiceException{
try{
Department t=ts.get(0);
if(checkDept(t)){
dao.update(t);
}
}
catch (DataAccessException e){
throw new MyExceptionHandler().process(e);
}catch (ServiceException e){
throw e;
}
}
}
顯示從上面的代碼可以得知數(shù)據(jù)接口業(yè)務(wù)邏輯圖,增刪改插這些方法可以從l類中抽取出來,成為公共的的方法。
我們首先業(yè)務(wù)層定義一個泛型接口,例如我們命名為,具體步驟見前文,這里不再細(xì)說,其具體示例代碼如下
package com.yn.service.base;
import com.yn.exception.ServiceException;
import java.util.List;
public interface IBaseService<T> {
/**
* 查詢所有信息
*/
public List<T> getAll() throws ServiceException;
/**
* 條件查詢

*/
public List<T> getByCondition(T t) throws ServiceException;
/**
*返回總行數(shù)
*/
public int getTotal() throws ServiceException;
/**
* 批量刪除
*/
public void remove(List<Integer> ids) throws ServiceException;
/**
* 批量新增
*/
public void insert(List<T> ts) throws ServiceException;
/**
* 批量跟新
*/
public void update(List<T> ts) throws ServiceException;
}
有了一個通用的泛型接口作為業(yè)務(wù)層的方法標(biāo)準(zhǔn)之后,接下來,我們修改原有接口,讓其繼承通用的泛型類,即如下代碼所示。
package com.yn.service;
import com.yn.model.Department;
import com.yn.service.base.IBaseService;
public interface IDepartmentService extends IBaseService<Department> {
}
其UML關(guān)系圖如下,這意味著接口遵循泛型接口的所有標(biāo)準(zhǔn)。
我們再創(chuàng)建一個泛型類,該類實現(xiàn)業(yè)務(wù)層泛型接口。類中的所有方法是從l實現(xiàn)類抽取出來,并加以泛化得到的。使得該泛型類包含了可以被不同實體類型使用的通用方法的泛型實現(xiàn)。如下代碼所示。
package com.yn.service.impl.base;
import com.yn.dao.base.IBaseDao;
import com.yn.exception.MyExceptionHandler;
import com.yn.exception.ServiceException;
import com.yn.service.base.IBaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import java.util.List;
abstract public class BaseService<T> implements IBaseService<T> {
@Autowired
protected IBaseDao<T> baseDao;
/**
* 驗證類型T的對象內(nèi)部的所有字段的數(shù)據(jù)完整性。
*/
abstract protected boolean validate(T t) throws ServiceException;
/**
* 查詢所有實體
*/
@Override
public List<T> getAll() throws ServiceException {
try {
return baseDao.findAll();
} catch (DataAccessException e) {
throw new MyExceptionHandler().process(e);
}
}
/**
* 條件查詢實體信息
*/
@Override
public List<T> getByCondition(T t) throws ServiceException {
try{
return baseDao.findByCondition(t);
}catch(DataAccessException e){
throw new MyExceptionHandler().process(e);
}
}
/**
* 查詢所有記錄數(shù)
*/
public int getTotal() throws ServiceException{
try{
return baseDao.total();
}catch(DataAccessException e){
throw new MyExceptionHandler().process(e);
}
}
@Override
public void remove(List<Integer> ids) throws ServiceException{
try{
baseDao.delete(ids);
}catch (DataAccessException e){
throw new MyExceptionHandler().process(e);
}
}
/**
* 新增實體
*/
@Override
public void insert(List<T> ts) throws ServiceException {
try {
T t = ts.get(0);
if(validate(t)) {
baseDao.save(t);
}
}catch (DataAccessException e){
throw new MyExceptionHandler().process(e);
}catch(ServiceException e){
throw e;
}
}
/**
* 更新實體
*/
@Override
public void update(List<T> ts) throws ServiceException{
try{
T t=ts.get(0);
if(validate(t)){
baseDao.update(t);
}
}
catch (DataAccessException e){
throw new MyExceptionHandler().process(e);
}catch (ServiceException e){
throw e;
}
}
}
值得注意的是,是一個抽象類,該類中包含一個抽象方法,從原來l實現(xiàn)類的修改而來,我這里用了一個更為通用的方法名。該方法會被其他繼承的對象實現(xiàn)方法的特定業(yè)務(wù)邏輯。
還有另外一個重點就是的屬性,其引用的接口類型是,這是數(shù)據(jù)持久層中最頂層的接口,可以回顧一下前一篇的這個圖。業(yè)務(wù)層只需要通過該接口找到T指定類型子接口的配置文件。
接下來的工作就很簡單了,讓我們l實現(xiàn)類繼承抽象類并且實現(xiàn)專用于實體對象的方法。同時也實現(xiàn)了接口。
package com.yn.service.impl;
import com.yn.exception.ServiceException;
import com.yn.model.Department;
import com.yn.service.IDepartmentService;
import com.yn.service.impl.base.BaseService;
import com.yn.utils.StringUtils;
import org.springframework.stereotype.Service;
@Service("departmentServiceImpl")
public class DepartmentServiceImpl extends BaseService<Department> implements IDepartmentService {
@Override
protected boolean checkDept(Department dept) throws ServiceException {
if(dept.getName().isEmpty()){
throw new ServiceException("部門名稱為空");
}else if(StringUtils.isSpecChar(dept.getName())){
throw new ServiceException("部門名稱不能包含特殊字符");
}else if(dept.getPhone().isEmpty()){
throw new ServiceException("電話號碼不能為空");
}else if(!StringUtils.isPhone(dept.getPhone())){
throw new ServiceException("電話號碼格式不正確");
}else {
return true;
}
}
}
既然,l繼承了類中的通用方法,為什么還要多此一舉,再讓l實現(xiàn)接口呢?如下關(guān)系圖所示
試想一下,此時接口額外定義了這個方法。意味著l也實現(xiàn)了方法。如果我們向表現(xiàn)層的控制器公開接口類型的對象引用,那么控制器是通過接口的引用無法找到方法的。
而層向表示層公開接口類型的引用,不僅能夠調(diào)用接口定義的所有方法,還能夠調(diào)用特有的方法。