设计模式讲解与代码实践(九)——组合

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

1 目的

组合(Composite)实现了树形结构,使用户对单个对象和包含一组单个(或组合)对象的组合对象的处理具有一致性。

2 基本形态

组合的基本形态如类图2-1所示。
图2-1  组合类图
图2-1 组合类图

3 参与者

结合图2-1,下面介绍各类在组合设计模式中扮演的角色。
3.1 Component
Component是组件接口,声明了各组合组件对其“组成部分”的管理方法,如Add 、Remove、GetChild等;同时,Component还声明了组合组件和叶子组件(非组合组件)的统一业务操作。
注意,在实际的应用中,Component也可以是包含了各接口实现的普通类。这在存在多个“组合组件”类型的场景下非常常见,有利于重用“组成部分”的管理方法。
3.2 Composite
Composite是组合组件,实现Component接口(或从其派生),作为组件的同时也是包含子组件的容器。
3.3 Leaf
Leaf是叶子组件,实现Component接口(或从其派生),作为单独的组件实现业务方法。
3.4 Client
Client是组合设计模式的使用者。它使用Component对象无差别的访问组合组件和叶子组件。

4 代码实践

下面我们用一个业务场景实例来进一步讲解组合的使用。
4.1 场景介绍
某组织机构管理模块包含对组织机构和所属人员的管理功能。其中,组织机构下可以包含子组织机构,也可以包含人员。比如本例中,组织“总公司”下包含子组织“财务部”,也可包含人员“张三”,而“财务部”包含人员“李四”。
以下各节将介绍该场景各类的具体实现及其在组合设计模式中所对应的参与者角色。
4.2 IOrgComponent
IOrgComponent是组织机构组件接口,除“添加子组织机构组件”、“删除子组织机构组件”、“获取子组织机构组件”等子组件管理方法外,还声明了“获取组织机构组件信息(json字符串)”和“获取组织机构名称”两个业务方法。对应于组合模式的参与者,IOrgComponent是组件接口Component。下面的代码给出了IOrgComponent的声明。

package demo.designpattern.composite;

import java.util.List;

/**
 * 组织机构组件
 * Created by LiMingzi on 2017/7/19.
 */
public interface IOrgComponent {
    /**
     *  添加子组织机构组件
     *  @param orgComponent 组织机构组件
     */
    void add(IOrgComponent orgComponent);

    /**
     * 删除子组织机构组件
     * @param orgComponent 组织机构组件
     */
    void remove(IOrgComponent orgComponent);

    /**
     * 获取子组织机构组件
     * @return 子组织机构集合
     */
    List<IOrgComponent> getChildOrgComponents();

    /**
     * 获取组织机构组件信息(json字符串)
     * @return 组织机构组件信息(json字符串)
     */
    String getOrgComponentInfo();

    /**
     * 获取组织机构名称
     * @return 组织机构名称
     */
    String getOrgComponentName();
}

4.3 Org
Org是组织机构类,实现了IOrgComponent接口。对应于组合模式的参与者,Org是组合组件Composite。下面的代码给出了Org的声明。

package demo.designpattern.composite;

import java.util.ArrayList;
import java.util.List;

/**
 * 组织机构类
 * Created by LiMingzi on 2017/7/19.
 */
public class Org implements IOrgComponent{
    /**
     * 组织名
     */
    private String name;

    /**
     * 组织名
     * @param name
     */
    public Org(String name) {
        this.name = name;
    }

    /**
     * 子组织机构集合
     */
    private List<IOrgComponent> childOrgComponents = new ArrayList<IOrgComponent>();

    /**
     * 添加子组织机构组件
     *
     * @param orgComponent 组织机构组件
     */
    @Override
    public void add(IOrgComponent orgComponent) {
        childOrgComponents.add(orgComponent);
    }

    /**
     * 删除子组织机构组件
     *
     * @param orgComponent 组织机构组件
     */
    @Override
    public void remove(IOrgComponent orgComponent) {
        for (int i = 0; i < childOrgComponents.size(); i++) {
            if(childOrgComponents.get(i).getOrgComponentName().equals(orgComponent.getOrgComponentName())){
                childOrgComponents.remove(i);
            }
        }
    }

    /**
     * 获取子组织机构组件
     *
     * @return 子组织机构集合
     */
    @Override
    public List<IOrgComponent> getChildOrgComponents() {
        return childOrgComponents;
    }

    /**
     * 获取组织机构组件信息(json字符串)
     *
     * @return 组织机构组件信息(json字符串)
     */
    @Override
    public String getOrgComponentInfo() {
        // 组织信息
        String orgInfo="{'NAME':'"+getOrgComponentName()+"','TYPE':'组织','CHILDREN':[";
        // 子组件
        List<IOrgComponent> childOrgComponents = getChildOrgComponents();
        for (int i = 0; i < childOrgComponents.size(); i++) {
            if(i>0){
                orgInfo+=",";
            }
            orgInfo+=childOrgComponents.get(i).getOrgComponentInfo();
        }
        orgInfo+="]}";
        return orgInfo;
    }

    /**
     * 获取组织机构名称
     *
     * @return 组织机构名称
     */
    @Override
    public String getOrgComponentName() {
        return name;
    }
}

上述代码中,69行实现了获取组织机构信息接口getOrgComponentInfo。它首先输出了自有属性NAME和TYPE,再遍历获取包含的各子组织机构组件的信息。不难看出,对于子组织机构组件仍是Org对象的情况,这将是一个隐式的递归调用。
4.4 User
User是用户类,实现了IOrgComponent接口。对应于组合模式的参与者,User是叶子组件Leaf。下面的代码给出了User的声明。

package demo.designpattern.composite;

import java.util.List;

/**
 * 用户类
 * Created by LiMingzi on 2017/7/19.
 */
public class User implements IOrgComponent{
    /**
     * 用户id
     */
    private String id;
    /**
     * 用户名
     */
    private String name;

    /**
     * 构造方法
     * @param id 用户id
     * @param name 用户名
     */
    public User(String id, String name) {
        this.id = id;
        this.name = name;
    }

    /**
     * 添加子组织机构组件
     *
     * @param orgComponent 组织机构组件
     */
    @Override
    public void add(IOrgComponent orgComponent) {

    }

    /**
     * 删除子组织机构组件
     *
     * @param orgComponent 组织机构组件
     */
    @Override
    public void remove(IOrgComponent orgComponent) {

    }

    /**
     * 获取子组织机构组件
     *
     * @return 子组织机构集合
     */
    @Override
    public List<IOrgComponent> getChildOrgComponents() {
        return null;
    }

    /**
     * 获取组织机构组件信息(json字符串)
     *
     * @return 组织机构组件信息(json字符串)
     */
    @Override
    public String getOrgComponentInfo() {
        // 用户信息
        String userInfo="{'NAME':'"+getOrgComponentName()+"','TYPE':'用户','ID':'"+id+"'}";
        return userInfo;
    }

    /**
     * 获取用户名
     *
     * @return 用户名
     */
    @Override
    public String getOrgComponentName() {
        return name;
    }
}

User类是Leaf类,因此各组成部分的管理方法对其并不适用。所以,上述代码中,第35、45、55行对组成部分的管理方法在实现上并无实际意义。而65行的业务方法getOrgComponentInfo也只是返回了用户的信息,不再嵌套返回其“子组件”信息。
4.5 OrgMgmt
OrgMgmt是组织机构管理类,实现了组织机构树输出功能。对应于组合模式的参与者,OrgMgmt是Client。下面的代码给出了OrgMgmt的声明。

package demo.designpattern.composite;

/**
 * 组织机构管理类
 * Created by LiMingzi on 2017/7/19.
 */
public class OrgMgmt {
    /**
     * 获取指定名称的组织机构组件,demo
     * @param name 组织机构组件名称
     * @return 组织机构组件
     */
    private IOrgComponent getOrg(String name){
        // 组织机构组件
        IOrgComponent orgComponent=null;
        // demo
        if(name.equals("总公司")){
            orgComponent = new Org("总公司");
            // 张三
            User userA = new User("001","张三");
            orgComponent.add(userA);
            // 财务部
            Org financeDep = new Org("财务部");
            orgComponent.add(financeDep);
            // 李四
            User userB = new User("002","李四");
            financeDep.add(userB);
        }
        return orgComponent;
    }

    /**
     * 输出组织机构树
     * @param rootName 作为根的组织机构名称
     */
    public void outputOrgTree(String rootName){
        // 根组织
        IOrgComponent rootOrg = getOrg(rootName);
        if(rootOrg!=null){
            System.out.println(rootOrg.getOrgComponentInfo());
        }
    }
}

上述代码中,36行,声明了输出组织机构树的方法outputOrgTree。outputOrgTree根据组织名称获取组织机构组件IOrgComponent 的对象rootOrg ,再调用其业务方法getOrgComponentInfo递归的输出该组织及其所有子孙组织、用户的信息。13行,获取指定名称的组织机构组件方法getOrg是一个演示方法,虚拟构建了“总公司”的组织机构树。需要注意的是,在实际的应用中,构建这样一棵树,应该一次性的从持久层抓取符合条件的组织机构和用户,再在内存中进行对象化。切忌逐层多次I/O操作,那样会带来极大的效率损失。
4.6 测试代码
为了测试本文中的代码,我们可以编写如下测试代码。

    /**
     * 组合测试
     */
    public static void compositeTest(){
        // 组织管理类
        OrgMgmt orgMgmt = new OrgMgmt();
        orgMgmt.outputOrgTree("总公司");
    }

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

{'NAME':'总公司','TYPE':'组织','CHILDREN':[{'NAME':'张三','TYPE':'用户','ID':'001'},{'NAME':'财务部','TYPE':'组织','CHILDREN':[{'NAME':'李四','TYPE':'用户','ID':'002'}]}]}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值