您的位置:首页 > 编程语言

设计模式讲解与代码实践(六)——适配器(基于类)

2017-07-10 17:11 507 查看
本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!

1 目的

适配器(Adapter)提供了将一个接口转换为另一个接口的方法。

2 基本形态

适配器(基于类)的基本形态如类图2-1所示。



图2-1 适配器(基于类)类图

3 参与者

结合图2-1,下面介绍各类在适配器(基于类)设计模式中扮演的角色。

3.1 Target

Target是目标接口,即希望转换成的接口,其中声明了需要实现的各接口方法。

3.2 Adaptee

Adaptee是原接口。这里所说的“接口”是广义的接口,实际上,Adaptee为包含各方法实现的具体类。一般来说,Adaptee基本包含了目标接口需要的功能,但方法的名称、参数、返回值可能不同。

3.3 Adapter

Adapter是适配器。它派生于Adaptee并实现了Target接口。Adapter在实现Target各接口方法时通过重组参数、返回值的形式调用了从Adaptee继承的相同业务功能的方法。

3.4 Client

Client是适配器设计模式的使用者。它使用Adapter类实例化Target接口,进而调用Target中声明的各方法实现业务功能。

4 代码实践

下面我们用一个业务场景实例来进一步讲解适配器的使用。

4.1 场景介绍

某OA系统可与不同的HR系统集成,用户信息由HR系统维护,用户的组织结构关系由OA系统维护。

以下各节将介绍该场景各类的具体实现及其在适配器设计模式中所对应的参与者角色。

4.2 IUserMgmt

IUserMgmt是用户管理接口,声明了“添加用户”等用户操作方法。对应于适配器模式的参与者,IUserMgmt是我们的目标接口Target。下面的代码给出了IUserMgmt的声明。

package demo.designpattern.adapter;

/**
* 目标用户管理接口
* Created by LiMingzi on 2017/7/6.
*/
public interface IUserMgmt {
/**
* 添加用户
* @param name 用户名
* @return 新用户id
* @throws RuntimeException 添加失败,message为失败原因
*/
public String addUser(String name) throws RuntimeException;
}


4.3 UserOperation

UserOperation是HR(原系统)的用户操作类,声明了用户操作的各方法。对应于适配器模式的参与者,UserOperation是我们的原接口Adaptee。下面的代码给出了UserOperation的声明。

package demo.designpattern.adapter;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
* 原系统用户操作类
* Created by LiMingzi on 2017/7/6.
*/
public class UserOperation {
/**
* 用户字典,key为用户名,value为用户流水
*/
private Map<String,Integer> userMap;

/**
* 构造方法
*/
public UserOperation() {
initUserMap();
}

/**
* 初始化用户字典,演示示例
*/
private void initUserMap(){
userMap=new HashMap<String, Integer>();
userMap.put("张三",1);
}

/**
* 插入用户
* @param name 用户名
* @return 插入是否成功
*/
public boolean insertUser(String name){
// 操作结果
boolean operation;
try {
userMap.put(name, getMaxUserSn()+1);
operation=true;
}catch (Exception ex){
operation=false;
}
return operation;
}

/**
* 获取最大流水
* @return 最大流水号
*/
private int getMaxUserSn(){
return Collections.max(userMap.values());
}

/**
* 获取用户流水码
* @param name 用户名
* @return 流水码,为0时表示用户不存在
*/
public int getUserSn(String name){
// 用户流水码
int sn = 0;
if(userMap.containsKey(name)){
sn = userMap.get(name);
}
return sn;
}
}


上述代码中,15行声明了该类以成员变量形式维护的用户集合,其中包含用户名及用户流水。27行,初始化用户字典方法为演示方法,添加了默认用户。实际代码中应为从数据库等持久层载入用户数据。37行插入用户的实现也与此类似,仅为演示使用。

4.4 UserOperationAdapter

UserOperationAdapter类是用户操作适配器类,主要声明了添加用户的方法addUser。UserOperationAdapter类从UserOperation类派生,实现了IUserMgmt接口。对应于适配器模式的参与者,UserOperationAdapter是我们的适配器Adapter。下面的代码给出了UserOperationAdapter的声明。

package demo.designpattern.adapter.forclass;

import demo.designpattern.adapter.IUserMgmt;
import demo.designpattern.adapter.UserOperation;

/**
* 用户操作适配器
* Created by LiMingzi on 2017/7/6.
*/
public class UserOperationAdapter extends UserOperation implements IUserMgmt {
/**
* 添加用户
*
* @param name 用户名
* @return 新用户id
* @throws RuntimeException 添加失败,message为失败原因
*/
@Override
public String addUser(String name) throws RuntimeException {
// 用户流水
int userSn = getUserSn(name);
// 用户已存在
if(userSn>0){
throw new RuntimeException("用户已存在,添加用户失败");
}
if(!insertUser(name)){
throw new RuntimeException("未知错误,添加用户失败");
}
userSn = getUserSn(name);
return Integer.toString(userSn);
}
}


上述代码中,19行实现了IUserMgmt 接口的addUser方法。21行使用从UserOperation继承的方法getUserSn获取了用户的流水号,23行通过流水号是否大于0判断用户是否已经存在。我们可以看到,通过adapter的包装,原接口的添加用户方法已被适配成满足目标接口的方法。本例中,不但方法名称、返回值、异常等元素被转换,内部判断逻辑也做了少许改动。

4.5 UserRegister

UserRegister是用户注册类,实现了用户注册功能。对应于适配器模式的参与者,UserRegister是Client。下面的代码给出了UserRegister的声明。

package demo.designpattern.adapter;

import demo.designpattern.adapter.IUserMgmt;

/**
* 用户注册类
* Created by LiMingzi on 2017/7/6.
*/
public class UserRegister {
/**
* 构造方法
* @param userMgmt 用户管理对象
*/
public UserRegister(IUserMgmt userMgmt) {
this.userMgmt = userMgmt;
}
/**
* 用户管理对象
*/
private IUserMgmt userMgmt;
/**
* 注册新用户
* @param userName 用户名
* @param orgName 组织名
*/
public void registerUser(String userName, String orgName){
try{
// 用户id
String userId = userMgmt.addUser(userName);
addUser2Org(userId,orgName);
}catch (RuntimeException ex){
System.out.println("用户\""+userName+"\"注册失败:"+ex.getMessage()+";");
return;
}
System.out.println("用户\""+userName+"\"注册成功;");
}

/**
* 将用户添加到组织(demo)
* @param userId 用户id
* @param orgName 组织名
*/
private void addUser2Org(String userId,String orgName){
System.out.println("ID为\""+userId+"\"的用户被添加到组织\""+orgName+"\"中;");
}
}


上述代码中,14行,通过有参构造方法指定用户管理对象接口的实现类实例。26行,声明了主要的业务方法注册用户,其逻辑是,添加用户并获取用户id(29行),将用户注册到指定的组织(30行)。43行将用户添加到组织为演示方法,这里仅做了用户注册到组织的信息输出。

4.6 测试代码

为了测试本文中的代码,我们可以编写如下测试代码。

/**
* 适配器(基于类)测试
*/
public static void adapterForClassTest(){
// 用户管理对象
IUserMgmt userMgmt = new demo.designpattern.adapter.forclass.UserOperationAdapter();
// 用户注册类对象
UserRegister userRegister = new UserRegister(userMgmt);
userRegister.registerUser("张三","销售部");
System.out.println("-----------------------------------------------------------------------------");
userRegister.registerUser("李四","采购部");
}


编译运行后,得到如下测试结果:

用户”张三”注册失败:用户已存在,添加用户失败;

—————————————————————————–

ID为”2”的用户被添加到组织”采购部”中;

用户”李四”注册成功;

5 扩展

5.1 对被适配接口的支持

基于类实现的适配器设计模式很容易实现“对被适配接口的支持”。基于类实现的适配器在实现了目标适配器接口的同时从原接口实现类派生,因此适配器支持原接口是很自然的。

需要注意,如果在实现目标接口时,对原接口实现类中的方法做了重写,则可能原接口的逻辑已被改变,从而失去了原接口的完整性,也就不再支持被适配接口了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息