设计模式讲解与代码实践(八)——桥接

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

1 目的

桥接(Bridge)将抽象类与它的实现类分离,使接口与实现可以独立扩展。

2 基本形态

桥接的基本形态如类图2-1所示。
图2-1  桥接类图
图2-1 桥接类图

3 参与者

结合图2-1,下面介绍各类在桥接设计模式中扮演的角色。
3.1 Abstraction
Abstraction是抽象类,定义我们希望实现的各接口方法。这里所说的“抽象类”是指广义的抽象。其实,一般情况下Abstraction是包含具体实现的普通类。它包含一个实现类(或接口)类型的成员变量,通过调用该实现类的方法实现自己的方法。
3.2 RefinedAbstraction
RefinedAbstraction是扩充的抽象类。它派生于Abstraction,扩充了抽象类定义。
3.3 Implementor
Implementor是实现类接口,它定义了Abstraction各方法中要用到的方法。
3.4 ConcreteImplementor
ConcreteImplementorA和ConcreteImplementorB是实现类的具体类,实现了实现类接口。
3.5 Client
Client是桥接设计模式的使用者。它使用ConcreteImplementor作为构造方法实参实例化Abstraction,从而调用Abstraction的方法实现业务功能。

4 代码实践

下面我们用一个业务场景实例来进一步讲解桥接的使用。
4.1 场景介绍
某电商平台“用户控制器”包含“注册组织和用户”功能。该功能需要对普通用户和vip用户分别处理。同时,对于“内部用户”和“外部用户”,底层有不同的存储逻辑。
以下各节将介绍该场景各类的具体实现及其在桥接设计模式中所对应的参与者角色。
4.2 UserMgmt
UserMgmt是用户管理类,声明了“注册用户”、“获取用户信息”等方法。对应于桥接模式的参与者,UserMgmt是我们的抽象类Abstraction。下面的代码给出了UserMgmt的声明。

package demo.designpattern.bridge;

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

/**
 * 用户管理类
 * Created by LiMingzi on 2017/7/14.
 */
public class UserMgmt {
    /**
     * 构造方法
     * @param userOperation 用户操作类对象
     */
    public UserMgmt(IUserOperation userOperation) {
        this.userOperation = userOperation;
    }

    /**
     * 用户操作类对象
     */
    private IUserOperation userOperation;
    /**
     * 注册用户
     * @param userId 用户id
     * @param userName 用户名
     * @param orgId 组织id
     */
    public void registerUser(String userId,String userName,String orgId){
        userOperation.addUser(userId,userName);
        userOperation.addUserToOrg(userId,orgId);
    }

    /**
     * 获取用户信息
     * @param userId 用户id
     */
    public String getUserInfo(String userId){
        return "用户id:"+userId+";用户姓名:"+userOperation.getUserName(userId)+";所属组织id:"+userOperation.getOrgOfUser(userId)+";";
    }
}

从上面代码中可以看到,UserMgmt虽然是 “抽象类”,但它是包含了实现的具体类。22行,声明了实现类接口类型的成员变量,而它是通过15行的构造方法实例化的。从29行、38行的方法实现可以看到,UserMgmt对实现类方法的调用不是直接“转发”,而是对方法进行了“组合”,这也是桥接模式的一般形式——抽象类与实现类定义并不相同。
4.3 VipUserMgmt
VipUserMgmt是VIP用户管理类,派生于UserMgmt,声明了“获取用户折扣率”方法并重写了“获取用户信息”方法。对应于桥接模式的参与者,VipUserMgmt是扩充的抽象类RefinedAbstraction。下面的代码给出了VipUserMgmt的声明。

package demo.designpattern.bridge;

/**
 * vip用户管理类
 * Created by LiMingzi on 2017/7/14.
 */
public class VipUserMgmt extends UserMgmt {
    /**
     * 构造方法
     *
     * @param userOperation 用户操作类对象
     */
    public VipUserMgmt(IUserOperation userOperation) {
        super(userOperation);
    }

    /**
     * 获取用户折扣率(demo)
     * @param userId 用户id
     * @return 折扣率
     */
    public float getUserDiscountRate(String userId){
        if("001".equals(userId)){
            return 0.2f;
        }
        else{
            return 0.1f;
        }
    }

    /**
     * 获取用户信息
     *
     * @param userId 用户id
     */
    @Override
    public String getUserInfo(String userId) {
        return super.getUserInfo(userId)+"折扣率:"+getUserDiscountRate(userId)+";";
    }
}

4.4 IUserOperation
IUserOperation是用户操作接口,声明了用户操作的各方法。对应于桥接模式的参与者,IUserOperation是实现类接口Implementor。下面的代码给出了IUserOperation的声明。

package demo.designpattern.bridge;

/**
 * 用户操作接口
 * Created by LiMingzi on 2017/7/14.
 */
public interface IUserOperation {
    /**
     * 添加用户
     * @param id 唯一标识
     * @param name 姓名
     */
    public void addUser(String id,String name);

    /**
     * 将用户添加到组织
     * @param userId 用户id
     * @param orgId 组织id
     */
    public void addUserToOrg(String userId,String orgId);

    /**
     * 获取用户名
     * @param id 用户id
     * @return 用户名
     */
    public String getUserName(String id);
    /**
     * 获取用户所属组织id
     * @param userId 用户id
     * @return 用户所属组织id
     */
    public String getOrgOfUser(String userId);
}

4.5 InnerUserOperation
InnerUserOperation类是内部用户操作类,实现了IUserOperation接口。对应于桥接模式的参与者,InnerUserOperation是具体实现类ConcreteImplementor。下面的代码给出了InnerUserOperation的声明。

package demo.designpattern.bridge;

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

/**
 * 内部用户操作类
 * Created by LiMingzi on 2017/7/14.
 */
public class InnerUserOperation implements IUserOperation{
    /**
     * 用户字典
     */
    private Map<String,String> userMap = new HashMap<String, String>();

    /**
     * 用户到组织机构字典,key为用户id,value为组织id
     */
    private Map<String,String>user2OrgMap = new HashMap<String, String>();

    /**
     * 添加用户
     *
     * @param id   唯一标识
     * @param name 姓名
     */
    @Override
    public void addUser(String id, String name) {
        // 数据库操作
        System.out.println("insert into inneruser (id,name) values('"+id+"','"+name+"')");
        // demo
        userMap.put(id,name);
    }

    /**
     * 将用户添加到组织
     *
     * @param userId 用户id
     * @param orgId  组织id
     */
    @Override
    public void addUserToOrg(String userId, String orgId) {
        // 数据库操作
        System.out.println("update inneruser set org='"+orgId+"' where id = '"+userId+"'");
        // demo
        user2OrgMap.put(userId,orgId);
    }

    /**
     * 获取用户名
     *
     * @param id 用户id
     * @return 用户名
     */
    @Override
    public String getUserName(String id) {
        // 数据库操作
        System.out.println("select name from inneruser where id = '"+id+"'");
        // demo
        return userMap.get(id);
    }

    /**
     * 获取用户所属组织id
     *
     * @param userId 用户id
     * @return 用户所属组织id
     */
    @Override
    public String getOrgOfUser(String userId) {
        // 数据库操作
        System.out.println("select org from inneruser where id = '"+userId+"'");
        // demo
        return user2OrgMap.get(userId);
    }
}

上述代码中,对名为inneruser 的内部用户表进行了插入、更新、查找等操作。inneruser 表包含的主要字段及含义为:id——用户id;name——用户名;org——用户所属组织机构id。因为该例为演示demo,故所有的数据库操作均为伪操作,仅输出对应的sql语句,实际操作以map存取代替。
4.6 OuterUserOperation
OuterUserOperation类是外部用户操作类,实现了IUserOperation接口。对应于桥接模式的参与者,OuterUserOperation是具体实现类ConcreteImplementor。下面的代码给出了OuterUserOperation的声明。

package demo.designpattern.bridge;

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

/**
 * 外部用户操作类
 * Created by LiMingzi on 2017/7/16.
 */
public class OuterUserOperation implements IUserOperation {
    /**
     * 用户字典
     */
    private Map<String,String> userMap = new HashMap<String, String>();

    /**
     * 用户到组织机构字典,key为用户id,value为组织id
     */
    private Map<String,String>user2OrgMap = new HashMap<String, String>();

    /**
     * 添加用户
     *
     * @param id   唯一标识
     * @param name 姓名
     */
    @Override
    public void addUser(String id, String name) {
        // 数据库操作
        System.out.println("insert into outeruser (user_id,user_name) values('"+id+"','"+name+"')");
        // demo
        userMap.put(id,name);
    }

    /**
     * 将用户添加到组织
     *
     * @param userId 用户id
     * @param orgId  组织id
     */
    @Override
    public void addUserToOrg(String userId, String orgId) {
        // 数据库操作
        System.out.println("insert into outeruser_org (user_id,org_id) values('"+userId+"','"+orgId+"')");
        // demo
        user2OrgMap.put(userId, orgId);
    }

    /**
     * 获取用户名
     *
     * @param id 用户id
     * @return 用户名
     */
    @Override
    public String getUserName(String id) {
        // 数据库操作
        System.out.println("select user_name from outeruser where user_id = '"+id+"'");
        // demo
        return userMap.get(id);
    }

    /**
     * 获取用户所属组织id
     *
     * @param userId 用户id
     * @return 用户所属组织id
     */
    @Override
    public String getOrgOfUser(String userId) {
        // 数据库操作
        System.out.println("select org_id from outeruser_org where user_id = '"+userId+"'");
        // demo
        return user2OrgMap.get(userId);
    }
}

从上面的代码可以看到,外部用户的存储结构与内部用户的存储结构是完全不同的。外部用户存储于表outeruser 中,该表的主要字段及含义为:user_id——用户id;user_name——用户名。而用户所属组织机构存储与“外部用户组织映射表” outeruser_org中,该表的主要字段及含义为:user_id——用户id;org_id——组织id。
4.7 UserController
UserController是用户控制器类,实现了注册组织用户功能。对应于桥接模式的参与者,UserController是Client。下面的代码给出了UserController的声明。

package demo.designpattern.bridge;

import java.util.UUID;

/**
 * 用户控制器
 * Created by LiMingzi on 2017/7/16.
 */
public class UserController {
    /**
     * 注册组织和用户
     * @param orgName 组织名
     * @param userName 用户名
     * @param isVip 是否为vip
     * @param isInner 是否为内部用户
     * @return 用户信息
     */
    public String registerOrgAndUser(String orgName, String userName, boolean isVip, boolean isInner) {
        // 用户操作对象
        IUserOperation userOperation = isInner ? new InnerUserOperation() : new OuterUserOperation();
        // 用户管理对象
        UserMgmt userMgmt = isVip ? new VipUserMgmt(userOperation) : new UserMgmt(userOperation);
        //TODO :查看组织是否存在,不存在则注册组织,并返回组织id
        // 组织id,demo
        String orgId = UUID.randomUUID().toString();
        // 用户id
        String userId = UUID.randomUUID().toString();
        userMgmt.registerUser(userId, userName, orgId);
        return userMgmt.getUserInfo(userId);
    }
}

上述代码中,20行,根据用户是内部用户还是外部用户用不同的实现类对象实例化接口IUserOperation 。22行,根据用户是否为VIP用户用不同的抽象类对象实例化抽象类UserMgmt。28行,注册用户,29行返回用户信息。
4.8 测试代码
为了测试本文中的代码,我们可以编写如下测试代码。

/** 
 * 桥接测试 
 */  
public static void bridgeTest(){  
    // 用户控制器  
    UserController userController = new UserController();  
    System.out.println(userController.registerOrgAndUser("采购部","张三",true,true));  
    System.out.println("-----------------------------------------------------------------------------");  
    System.out.println(userController.registerOrgAndUser("销售部","李四",false,false));  
}  

编译运行后,得到如下测试结果:
insert into inneruser (id,name) values(‘bc20fecb-430b-492d-bee5-6a03063ef3d5’,’张三’)
update inneruser set org=’1746161d-695e-41b8-9d63-09ce21625047’ where id = ‘bc20fecb-430b-492d-bee5-6a03063ef3d5’
select name from inneruser where id = ‘bc20fecb-430b-492d-bee5-6a03063ef3d5’
select org from inneruser where id = ‘bc20fecb-430b-492d-bee5-6a03063ef3d5’
用户id:bc20fecb-430b-492d-bee5-6a03063ef3d5;用户姓名:张三;所属组织id:1746161d-695e-41b8-9d63-09ce21625047;折扣率:0.1;


insert into outeruser (user_id,user_name) values(‘2e1c261f-934f-42c7-97b7-e708a1dbd60c’,’李四’)
insert into outeruser_org (user_id,org_id) values(‘2e1c261f-934f-42c7-97b7-e708a1dbd60c’,’5d6867eb-4acc-49d5-b6cd-56e1bd7ce887’)
select user_name from outeruser where user_id = ‘2e1c261f-934f-42c7-97b7-e708a1dbd60c’
select org_id from outeruser_org where user_id = ‘2e1c261f-934f-42c7-97b7-e708a1dbd60c’
用户id:2e1c261f-934f-42c7-97b7-e708a1dbd60c;用户姓名:李四;所属组织id:5d6867eb-4acc-49d5-b6cd-56e1bd7ce887;

5 扩展

5.1 与适配器的辨析
桥接与适配器主要包含以下区别:

  1. 桥接一般用于设计之初,此时无论抽象类还是实现类均未开发;适配器一般用于原接口已开发完成而目标接口尚未开发;
  2. 桥接强调抽象类与实现类各自扩展;适配器并不存在扩展的概念,强调包装;
  3. 桥接的抽象类与实现类可以以不同的概念进行划分,比如本例中抽象类以用户VIP类别进行划分,而实现类则以内、外部用户进行划分;适配器一般不会做这种划分,即便划分也不在适配器的描述范围以内;
  4. 桥接的抽象类与实现类所包含的方法通常可以完全不同;适配器的目标接口与原接口则应尽可能一致,最理想的状态是仅作接口转发。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值