设计模式:(组合模式)

1.定义

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
简单来说:将对象组合成树形结构以表示整体-部分结构的层次结构。Composite使用户对单个对象和组合对象的使用具有一致性。

2.概述

如果一个对象包含另一个对象的引用,称这样的对象为组合对象。如果将当前组合对象作为一个整体的话,那么它所包含的对象就是该整体的一部分。如果一个对象不包含有其他对象的引用,称这样的对象为个体对象。在编写程序时,我们希望将许多个体对象和组合对象组成树形结构,一次表示部分-整体的层次结构,并借助该层次结构使得用户能够用一致的方式处理个体对象和组合对象。在组成的树形结构中,个体对象和组合对象都是树中的节点,但是组合对象具有其他子节点的节点,个体对象是不具有其他子节点的叶节点,也就是说在树形结构中,组合对象所包含的对象将作为该组合对象的子节点被对待。

3.应用场景

部分、整体场景,如树形菜单,文件、文件夹的管理。

4.模式的结构与使用

组合模式包括三种角色。
抽象组件(Component): 是一个接口(抽象类),该接口(抽象类)定义了个体对象和组合对象需要实现的关于操作其子节点的方法,比如add()、remove()以及getChild()等方法。抽象组件也可以定义个体对象和组合对象用于操作器自身的方法,比如isLeaf()方法等。
Component节点(Component Node): 实现Component接口类的实例,Component节点不仅实现Component接口,而且可以含有其他Component节点或Leaf节点的引用。
Leaf节点(Leaf Node): 实现了Component接口类的实例,Leaf节点实现Component接口,不可以含有其他Component节点或Leaf节点的引用,因此叶节点在实现Component接口有关操作子节点的方法时,比如add(),remove()和getChild()方法,可让方法抛出一个异常,也可以实现为空操作。

1.组合模式的UML类图

在这里插入图片描述

2.结构的描述

以下通过一个简单的问题来描述怎样使用组合模式,这个问题就是用组合模式描述连队的军士结构,并计算军饷。一个连队由一个连长,两个排长,6个班长和60个士兵锁构成,一共69人。连长直接指挥2个排长,每个排长直接指挥3个班长,每个班长直接指挥10个士兵。连长的军饷是每月5000,排长是4000元,连长是2000元,士兵是1000元。现在使用功组合模式,让连队的军士形成树形结构,并计算一个班的军饷,一个连的军饷和整个连队的军饷。
1.抽象组件
本问题中,抽象组件(Component)的名字是MilitaryPerson,MilitaryPerson接口的代码如下所示:

import java.util.Iterator;

public interface MilitaryPerson {
    public void add(MilitaryPerson person);
    public void remove(MilitaryPerson person);
    public MilitaryPerson getChild(int index);
    public Iterator<MilitaryPerson> getAllChildren();
    public boolean isLeaf();
    public double getSalary();
    public void setSalary(double salary);
}

2.Composite节点
对于本问题,Composite节点是MilitaryOfficer类的实例,MilitaryOfficer类的代码如下:

import java.util.Iterator;
import java.util.LinkedList;

public class MilitaryOfficer implements MilitaryPerson{
    LinkedList<MilitaryPerson> list;
    String name;
    double salary;

    public MilitaryOfficer(String name, double salary) {
        this.name = name;
        this.salary = salary;
        list=new LinkedList<MilitaryPerson>();
    }

    @Override
    public void add(MilitaryPerson person) {
        list.add(person);
    }

    @Override
    public void remove(MilitaryPerson person) {
        list.remove(person);
    }

    @Override
    public MilitaryPerson getChild(int index) {
        return list.get(index);
    }

    @Override
    public Iterator<MilitaryPerson> getAllChildren() {
        return list.iterator();
    }

    @Override
    public boolean isLeaf() {
        return false;
    }

    @Override
    public double getSalary() {
        return salary;
    }

    @Override
    public void setSalary(double salary) {
        this.salary=salary;
    }
}

3.Leaf节点
对于本问题,Leaf节点是MilitarySoldier类的实例,MilitarySoldier类的代码如下所示:

import java.util.Iterator;

public class MilitarySoldier implements MilitaryPerson{
    //由于是叶子节点 无字节点队列
    double salary;
    String name;

    public MilitarySoldier(double salary, String name) {
        this.salary = salary;
        this.name = name;
    }

    @Override
    public void add(MilitaryPerson person) {
        //由于无字节点 空实现
    }

    @Override
    public void remove(MilitaryPerson person) {
        //由于无字节点 空实现
    }

    @Override
    public MilitaryPerson getChild(int index) {
        return null;
    }

    @Override
    public Iterator<MilitaryPerson> getAllChildren() {
        return null;
    }

    @Override
    public boolean isLeaf() {
        return true;
    }

    @Override
    public double getSalary() {
        return salary;
    }

    @Override
    public void setSalary(double salary) {
        this.salary=salary;
    }
}

4.测试程序

import java.util.Iterator;

public class Application {
    public static void main(String[] args) {
        MilitaryPerson 连长=new MilitaryOfficer("连长",5000);
        MilitaryPerson 排长1=new MilitaryOfficer("一排长",4000);
        MilitaryPerson 排长2=new MilitaryOfficer("二排长",4000);
        MilitaryPerson 班长11=new MilitaryOfficer("一班长",2000);
        MilitaryPerson 班长12=new MilitaryOfficer("二班长",2000);
        MilitaryPerson 班长13=new MilitaryOfficer("三班长",2000);
        MilitaryPerson 班长21=new MilitaryOfficer("一班长",2000);
        MilitaryPerson 班长22=new MilitaryOfficer("二班长",2000);
        MilitaryPerson 班长23=new MilitaryOfficer("三班长",2000);
        MilitaryPerson []士兵=new MilitarySoldier[60];
        for (int i = 0; i < 士兵.length; i++) {
            士兵[i]=new MilitarySoldier("小兵",1000);
        }
        连长.add(排长1);
        连长.add(排长2);
        排长1.add(班长11);
        排长1.add(班长12);
        排长1.add(班长13);
        排长2.add(班长21);
        排长2.add(班长22);
        排长2.add(班长23);
        for (int i = 0; i < 10; i++) {
            班长11.add(士兵[i]);
            班长12.add(士兵[i+10]);
            班长13.add(士兵[i+20]);
            班长21.add(士兵[i+30]);
            班长22.add(士兵[i+40]);
            班长23.add(士兵[i+50]);
        }
        System.out.println("一排的军饷"+ComputerSalary.computerSalary(排长1));
        System.out.println("一班的军饷"+ComputerSalary.computerSalary(班长11));
        System.out.println("一连的军饷"+ComputerSalary.computerSalary(连长));
    }
}


class ComputerSalary{//计算工资类
    public static double computerSalary(MilitaryPerson person){
        double sum=0;
        if(person.isLeaf()){
            sum+=person.getSalary();
        }else {
            sum+=person.getSalary();
            Iterator<MilitaryPerson> iterator = person.getAllChildren();
            while(iterator.hasNext()){
                MilitaryPerson p = iterator.next();
                sum+=computerSalary(p);
            }
        }
        return sum;
    }
}

5.测试结果展示
在这里插入图片描述

5.组合模式的优点

1.组合模式中包含个体对象和组合对象,并形成树形结构,使用户可以方便地处理个体对象和组合对象;
2.组合对象和个体对象实现了相同的接口,用户一般无须区别个体对象和组合对象;

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

散一世繁华,颠半世琉璃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值