我什么时候应该使用复合设计模式?

时间:2011-03-17 02:48:34

标签: design-patterns composite

我不明白何时应该使用复合设计模式我将从这种设计模式中获得哪些好处? 我访问了this website,但它只告诉我设计模式的结构,而不是使用它的场景。 我希望像我这样的程序员开始学习设计模式会有所帮助。

10 个答案:

答案 0 :(得分:66)

复合是一种模式,在您可能需要有选择地将一组属于层次结构的对象视为“相同”时,它们实际上是不同的时候是有用的。通常,所使用的示例在处理叶子和节点方面相同,但该模式也可以扩展到异构列表。

例如,考虑去看医生。当您去看医生时会发生各种各样的事情,您通常会先看护士或助理,他们会接受您的体温等等。然后医生会进行检查并进行诊断。然后医生可能会做一些治疗,但护士经常回来完成治疗。在访问期间执行不同的活动。您有重量和温度等观察结果。但是,例如实验室将是一个不同的对象,因为它通常需要一个样本,然后可以将其发送出去并要求在以后记录结果。

因此,我们拥有允许记录所有这些内容的软件,它通常会创建某种类型的层次结构,例如:

遭遇:
    PreExam
    考试
    治疗

在每个节点下,您将拥有各种条目,如诊断,观察,实验室程序,诊断,注射等。

这一切都很好,你最终会得到一个结构化的,虽然非常复杂的分层记录。

现在假设你需要生成账单。突然间,你面临着一个非常不同的要求。您的医疗记录需要创建一个非常准确的相遇图片。在计费中,虽然您不关心谁做了什么或以什么顺序执行,但实际上您并不关心除了结算代码之外的活动。您只需要一个可计费活动列表,即代码。

此信息不仅嵌入在记录中,而且该记录也很难遍历,因为它包含大量不同的对象。它在层次结构中也是可变的 - 如果你的头脑中有钉子,他们可能会跳过任何类型的预检,或者检查这个问题并去治疗。如果您进去拆除缝线,可能没有任何预考或考试。每年的身体没有治疗。等等。很难列举这种对象图。

复合模式解决了这一切。您可以为所有对象定义公共接口或基类。我们称之为“CareEntry”。 CareEntry有一个属性BillingCode。现在你的Encounter看起来是一个简单的容器,里面只有CareEntry对象。您的结算服务现在可以简单地枚举内部的所有内容,而无需担心某些内容是节点(PreExam,考试)与叶子(体重温度),或者对象所在的节点(PreExam考试等)或实际类型对象是(实验室,注射等)。一切都是CareEntry并统一对待 - 您只需枚举Encounter中的所有CareEntry对象,并收集每个具有非空帐单代码的对象,您就完成了。就这么简单。

答案 1 :(得分:30)

引自Design Patterns

  

时使用复合图案      
      
  • 您想要表示对象的部分整体层次结构。
  •   
  • 您希望客户能够忽略它们之间的区别   对象和组合   个别物件。客户会   处理复合中的所有对象   结构一致。
  •   

一种常见的用法是在书中用作激励的例子,图形窗口的显示系统可以包含其他窗口和图形元素,例如图像,文本。复合可以在运行时组合,客户端代码可以操作所有元素,而无需考虑它对于常见操作(如绘图)的类型。

答案 2 :(得分:18)

复合模式允许客户统一处理单个对象以及单个对象的组合 例如,双击文件夹时应该打开文件夹。在文件的两倍上,它应该在相应的程序中打开 操作相同,但基于它是单个对象还是组合

单个对象和复合对象的通用接口

interface Data{
    public void doubleClick();
}

单个对象实现

class File implements Data {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public void doubleClick() {
        System.out.println(this.getName()+" file is Opened in a Program ");
    }
}

复合实施

class Folder implements Data {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    private List<Data> folder = new ArrayList<Data>();

    @Override
    public void doubleClick() {
        System.out.println(this.getName() + " folder is Opened");
        for(Data data : folder) {
            data.doubleClick();
        }
    }

    public void add(Data data) {
        folder.add(data);
    }

    public void remove(Data data) {
        folder.remove(data);
    }
}

客户计划

public class CompositePattern {

    public static void main(String[] args) {

        Folder f1 = new Folder();f1.setName("Folder 1");
        Folder f2 = new Folder();f2.setName("Folder 2");
        Folder f3 = new Folder();f3.setName("Folder 3");

        File file1 = new File();file1.setName("File 1");
        File file2 = new File();file2.setName("File 2");
        File file3 = new File();file3.setName("File 3");
        File file4 = new File();file4.setName("File 4");

        f1.add(file1);
        f2.add(file2);

        f3.add(f2);
        f3.add(file3);
        f3.add(file4);

        f1.doubleClick();f2.doubleClick();f3.doubleClick();

    }

}

答案 3 :(得分:6)

我经常使用复合设计模式来隐藏集合。在许多情况下,当存在许多元素并且只有一个元素时,我们以完全相同的方式处理集合。

这就是问题所在,因为包含集合的类然后与foreach循环一起群集,这些循环基本上做同样的事情 - 遍历所有元素并应用一些聚合函数。

为了解决这个问题,我介绍了一个由单个元素实现的接口以及隐藏这些元素集合的类。然后,复合类的目的是包含以前在客户端类中的所有聚合函数。

您可以在本文中找到一些有用的示例:Working With Collections

这里常见的是,Composite不一定代表整体关系。可以引入复合元素只是为了将循环移出客户端。

以下是应用Composite模式隐藏复合元素后面部分的一本书的示例:Composite Design Pattern

答案 4 :(得分:3)

最近研究并尝试过它,我认识到一个强大的概念,要记住复合材料。

复合材料隐藏了集合中涉及的复杂性,即循环遍历它们,对它们进行排序,过滤一些等等,并允许您将其视为单个生物体。

说,你在一个狗窝里养了一只狗,在另一个狗窝养了很多只狗。你想喂它们并为它们接种疫苗,但如果它们在一小时内吃完就喂你不能喂它们,或者如果它们在最后五个小时内接种了它们就喂它们,或者如果它们呕吐等就接种它们。

更重要的是,在品种B之前有狗品种A吃的包装顺序有规则,除非品种C狗在周围并且吠到他的肺部顶部。

这很快就会达到这样的程度:你根本不想关心任何事情,只需打电话给帮助者并告诉他喂养所有的狗。或者更好的是,三个帮助者跟踪喂养,接种和呕吐,吠叫和包装以及所有其他令人敬畏的东西。

通过调出帮助器,您依赖于合成模式。你只需要去喂养&#39;每个狗窝,无论是一只狗还是十只狗。你只是想让狗窝里装满狗狗自己整理出来并弄清楚它们是如何喂食的,因为你手边的收银员太多了。

所以,对你来说,狗是一个IDog,谁是Feed(),Bark(),Vomit()和GetVaccine()。狗窝也是狗,你称之为kennel.Feed()。你完成了。狗窝犬舍必须在内部弄清楚该做些什么。它可能有一个时间保持机制,以跟踪每只狗的喂养和其他身体功能时间。它全部封装得很整齐。

答案 5 :(得分:2)

当您使用binary trees或其他complex data structures like list of lists of lists等等时,您可能会发现这是必须的.​​..然后,当每个元素(类)实现1个接口时,您可以执行此操作在1片叶子或整个群体上使用相同的方法 - 包括,添加,移除,移动......无论什么,你已经正确实现了什么。它非常实用和简单。

答案 6 :(得分:2)

答案应该是 -

将对象组合成树结构以表示整个部分层次结构。 Composite允许客户统一处理单个对象和对象组合。

  • 递归构图
  • “目录包含条目,每个条目都可以是目录。”
  • 1对多“有一个”向上“是一个”层次结构

从论坛复制。

答案 7 :(得分:2)

复合设计模式真实世界的例子, 当我们有机会在内部或组件类型中具有相同父类型的实例时。

实施例: 外汇交易系统Ex1

  

您可能拥有交叉货币对(澳元/欧元) = (澳元/美元和   1 /(EUR / USD))这里的要点是你的乐器(Cross)可以有两个   仪器(直接)内部。

在另一个例子中有

  

一台仪器(十字架)和仪器(直接)和仪器(十字架)   可以进一步分为拖曳仪器(直接)。 SGD / CZK =   美元/新元(直接)和美元/捷克克朗(交叉)=美元/新元(直接)和   (1 / EUR / USD)(直接)和EUR / CZK(直接)

这里的重点是你不断分开直到找不到所有直接货币对。

使用Composite Design模式可以轻松实现上述功能。

答案 8 :(得分:1)

答案 9 :(得分:1)

如果要构建嵌套的类似对象,则意味着可以使用复合设计模式 例如:如果您想基于层次结构

显示办公室员工的树结构,则实时显示