Fork me on GitHub

设计模式-组合模式(10)

定义

  组合(Composite Pattern)模式也叫合成模式,用来描述部分与整体的关系。英文原话是:Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual object and compositions of objects uniformly.意思是:将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性

  组合模式分为三个角色:

  1.抽象构件(Component)角色:该角色定义参加组合的对象的共有方法和属性,规范一些默认的行为接口。

  2.叶子构件(Leaf)角色:该角色是叶子对象,其下没有其他的分支,定义出参加组合的原始对象的行为。

  3.树枝构件(Composite)角色:该角色代表参加组合的、其下有分支的树枝对象,它的作用是将树枝和叶子组合成一个树形结构,并定义出管理子对象的方法,如add()、remove()等。

//定义抽象构建接口
public interface Component {
    public void operation();
}

/**
 * 树枝构件 
 */
public class Composite implements Component {
    //构建容器
    private ArrayList<Component> componentList = new ArrayList<Component>();
    //添加构件
    public void add(Component component){
        this.componentList.add(component);
    }
    //删除构件
    public void remove(Component component){
        this.componentList.remove(component);
    }
    //获取子构件
    public ArrayList<Component> getChild(){
        return this.componentList;
    }
    
    @Override
    public void operation() {
        //省略业务逻辑代码
        System.out.println(this.toString()+"树枝构建业务");
    }
}

/**
 * 叶子构件 
 */
public class Leaf implements Component {
    @Override
    public void operation() {
        //省略业务逻辑代码
        System.out.println(this.toString()+"叶子构建业务");
    }
}

/**
 * 调用 
 */
public class Client {

    public static void main(String[] args) {
        //创建一个跟节点
        Composite root = new Composite();
        root.operation();
        //创建树枝节点
        Composite branch = new Composite();
        //创建叶子节点
        Leaf leaf = new Leaf();
        //创建树形结构
        root.add(branch);
        branch.add(leaf);
        
        display(root);
    }
    
    //遍历树(递归)
    public static void display(Composite root){
        for (Component c:root.getChild()) {
            if (c instanceof Leaf) {    //如果节点类型是叶子节点
                c.operation();
            }else {    //树枝节点
                c.operation();
                display((Composite)c);
            }
        }
    }
}

源码

组合模式优点

  • 高层模块调用简单。一颗树形机构的所有节点都是Component,局部和整体对于调用者来说没有任何区别,即高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码。
  • 节点自由增加。使用组合模式后,如果想增加树枝节点、树叶节点,只需找到其父节点即可。

组合模式缺点

  • 不易控制树枝构件的类型。
  • 不易使用继承的方法来增加新的行为。

使用场景

  • 需要描述对象的部分和整体之间的等级结构关系,如树形菜单、文件和文件夹管理等。
  • 需要客户端忽略个体构件和组合构件的区别,平等的对待所有的构建。

  组合模式也是应用广泛的一种设计模式。例如,java基础类库的swing部分就是大量使用了组合模式,其中大部分控件都是JComponent的子类,同时其add()方法又可向界面添加JComponent类型的控件,从而使得使用者能够以统一的方式操作各种控件。

/**
 * 抽象接口
 */
public interface Company {
    //获取信息
    public String getInfo();
}

/**
 * 树枝节点类 
 */
public class ConcreteCompany implements Company{
    //构件容器
    private ArrayList<Company> companyList = new ArrayList<Company>();
    
    private String name;
    private String sex;
    private String position;
    private int salary;
    
    public ConcreteCompany(String name,String sex, String position, int salary) {
        this.name = name;
        this.sex = sex;
        this.position = position;
        this.salary = salary;
    }
    
    //添加构件
    public void add(Company company){
        this.companyList.add(company);
    }
    
    //删除构件
    public void remove(Company company){
        this.companyList.remove(company);
    }
    
    public ArrayList<Company> getChild(){
        return this.companyList;
    }
    
    //获取子构件
    @Override
    public String getInfo() {
        String info = "";
        info = "名称:"+this.name;
        info+="\t性别"+this.sex;
        info+="\t职位"+this.position;
        info+="\t薪水"+this.salary;
        return info;
    }

}

/**
 * 叶子节点类
 */
public class Employee implements Company{
    private String name;
    private String sex;
    private String position;
    private int salary;
    
    public Employee(String name,String sex, String position, int salary) {
        this.name = name;
        this.sex = sex;
        this.position = position;
        this.salary = salary;
    }
    
    @Override
    public String getInfo() {
        String info = "";
        info = "名称:"+this.name;
        info+="\t性别"+this.sex;
        info+="\t职位"+this.position;
        info+="\t薪水"+this.salary;
        return info;
    }

}

//调用
public class DemoClient {
    public static void main(String[] args) {
        //CEO
        ConcreteCompany root = new ConcreteCompany("李彦宏", "男", "CEO", 1000000);
        //部门经理
        ConcreteCompany developDep = new ConcreteCompany("郑亮", "男", "研发部经理", 9999999);
        ConcreteCompany salesDep = new ConcreteCompany("逍遥", "男", "销售部经理", 8888888);
        ConcreteCompany financeDep = new ConcreteCompany("小颖", "女", "财务不经理", 6666666);
        //部门员工
        Employee e1 = new Employee("程序甲", "男", "java开发工程师", 10000);
        Employee e2 = new Employee("素材乙", "女", "素材师", 8888);
        Employee e3 = new Employee("UI丙", "男", "UI设计师", 8888);
        Employee e4 = new Employee("销售员甲", "男", "销售员", 6666);
        Employee e5 = new Employee("销售员乙", "男", "销售员", 6666);
        Employee e6 = new Employee("会计甲", "男", "会计", 5000);
        //生成树
        root.add(developDep);
        root.add(salesDep);
        root.add(financeDep);
        developDep.add(e1);
        developDep.add(e2);
        developDep.add(e3);
        salesDep.add(e4);
        salesDep.add(e5);
        financeDep.add(e6);
        //递归树
        display(root);
    }
    //遍历树(递归)
    public static void display(ConcreteCompany root){
        for (Company c:root.getChild()) {
            if (c instanceof Employee) {
                System.out.println(c.getInfo());
            }else {    //树枝节点
                System.out.println("\n"+c.getInfo());
                display((ConcreteCompany) c);
            }
        }
    } 
    
}

源码

 

posted @ 2017-12-07 23:12  秋夜雨巷  阅读(203)  评论(0编辑  收藏  举报