在java里Composite是啥

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在java里Composite是啥相关的知识,希望对你有一定的参考价值。

Composite是java设计的组合模式,将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

参考技术A 1.composite模式意在组成任意复杂度的整体--部分组件层次结构,同时将单个组件或复合组件视为统一的接口。树形组织结构就是其中一种表现形式。

树形结构中有叶子结点和非叶子结点(根结点是特例),非叶子结点可以添加,删除(add(),delete())子结点,获取子结点(getChild()),叶子结点没有;此外树结构的所有节点还有共同的操作(operator()).
用户界面通常由两种基本类型的组件构造:基本组件和容器组件,容器组件可以在其内部嵌套任意数目的组件,而基本组件则不行。使用这两种组件类型,开发者可以建立更强大的组件,进而创建多姿多彩的用户界面。
但是在与复杂的组件层次结构打交道时,必须在容器组件和基本组件之间进行区分,比较麻烦,composite提供了一种解决方案。适用它的情况:
a. 要表现“部分-整体”的层次结构时
b. 希望在事件组件层次中,同等对待复合组件与单个组件。

2. 通过下面的示例来理解
示例1:
基类shape 类有两个派生类Circle和Square(相当于叶子结点或者是单个组件),第三个派生类CompositeShape是个组合体(相当于非叶子结点或者是容器组件),它持有一个含有多个shape实例的列表,当调用CompositeShape中的draw()时,它就把这个方法委托给列表中的每一个实例。

对于系统而言,一个CompositeShape实例就像是一个独立的shape,可以把它传给使用shape的方法或者对象。实际上,它只是一组shape实例的proxy.
程序:

Shape.java:

Public interface Shape
Public void draw();


CompositeShape.java:
[code]Public class CompositeShape implements Shape
private Vector Comshape = new Vector();

public void add(Shape shape)
Comshape.add(shape);


Public void draw()
for( int i = 0; i < comshape.size(); i ++ )
Shape shape = (Shape) comshape.elementAt(i);
Shape.draw();


本回答被提问者采纳
参考技术B Composite是java设计的组合模式,将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
优点: 1.使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。
2.更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。
常见6个java类来描述说明Composite设计模式的实现方式;

1、 Circle.java 部件-圆
2、 Graph.java 部件-抽象类
3、 Line.java 部件-线
4、 Picture.java 部件-图
5、 Rectangle.java 部件-方
6、 PictureTest.java 带有main方法的测试类

例如:1、 Circle.java
package composite;//部件-圆
public class Circle extends Graph
public void draw()
System.out.println("Draw a circle.");

参考技术C Java设计模式之中的一种
工作原理是将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。这样会使得使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关系自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。而且更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。
参考技术D 是java的一种设计模式

Java设计模式之 — 组合(Composite)

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153753

 

听说你们公司最近新推出了一款电子书阅读应用,市场反应很不错,应用里还有图书商城,用户可以在其中随意选购自己喜欢的书籍。你们公司也是对此项目高度重视,加大了投入力度,决定给此应用再增加点功能。

 

好吧,你也知道你是逃不过此劫了,没过多久你的leader就找到了你。他告诉你目前的应用对每本书的浏览量和销售量做了统计,但现在想增加对每个书籍分类的浏览量和销售量以及所有书籍总的浏览量和销售量做统计的功能,希望你可以来完成这项功能。

 

领导安排的工作当然是推脱不掉的,你只能硬着头皮上了,不过好在这个功能看起来也不怎么复杂。

 

你比较喜欢看小说,那么就从小说类的统计功能开始做起吧。首先通过getAllNovels方法可以获取到所有的小说名,然后将小说名传入getBrowseCount方法可以得到该书的浏览量,将小说名传入getSaleCount方法可以得到该书的销售量。你目前只有这几个已知的API可以使用,那么开始动手吧!

[java] view plain copy
 
  1. public int getNovelsBrowseCount() {  
  2.     int browseCount = 0;  
  3.     List<String> allNovels = getAllNovels();  
  4.     for (String novel : allNovels) {  
  5.         browseCount += getBrowseCount(novel);  
  6.     }  
  7.     return browseCount;  
  8. }  
  9.   
  10. public int getNovelsSaleCount() {  
  11.     int saleCount = 0;  
  12.     List<String> allNovels = getAllNovels();  
  13.     for (String novel : allNovels) {  
  14.         saleCount += getSaleCount(novel);  
  15.     }  
  16.     return saleCount;  
  17. }  

很快你就写下了以上两个方法,这两个方法都是通过获取到所有的小说名,然后一一计算每本小说的浏览量和销售量,最后将结果相加得到总量。

 

小说类的统计就完成了,然后你开始做计算机类书籍的统计功能,代码如下所示:

[java] view plain copy
 
  1. public int getComputerBooksBrowseCount() {  
  2.     int browseCount = 0;  
  3.     List<String> allComputerBooks = getAllComputerBooks();  
  4.     for (String computerBook : allComputerBooks) {  
  5.         browseCount += getBrowseCount(computerBook);  
  6.     }  
  7.     return browseCount;  
  8. }  
  9.   
  10. public int getComputerBooksSaleCount() {  
  11.     int saleCount = 0;  
  12.     List<String> allComputerBooks = getAllComputerBooks();  
  13.     for (String computerBook : allComputerBooks) {  
  14.         saleCount += getSaleCount(computerBook);  
  15.     }  
  16.     return saleCount;  
  17. }  

除了使用了getAllComputerBooks方法获取到所有的计算机类书名,其它的代码基本和小说统计中的是一样的。

 

现在你才完成了两类书籍的统计功能,后面还有医学类、自然类、历史类、法律类、政治类、哲学类、旅游类、美食类等等等等书籍。你突然意识到了一些问题的严重性,工作量大倒还不算什么,但再这么写下去,你的方法就要爆炸了,这么多的方法让人看都看不过来,别提怎么使用了。

 

这个时候你只好向你的leader求助了,跟他说明了你的困惑。只见你的leader思考了片刻,然后自信地告诉你,使用组合模式不仅可以轻松消除你的困惑,还能出色地完成功能。

 

他立刻向你秀起了编码操作,首先定义一个Statistics接口,里面有两个待实现方法:

[java] view plain copy
 
  1. public interface Statistics {  
  2.   
  3.     int getBrowseCount();  
  4.       
  5.     int getSalesCount();  
  6.   
  7. }  

然后定义一个用于统计小说类书籍的NovelStatistics类,实现接口中定义的两个方法:

[java] view plain copy
 
  1. public class NovelStatistics implements Statistics {  
  2.   
  3.     @Override  
  4.     public int getBrowseCount() {  
  5.         int browseCount = 0;  
  6.         List<String> allNovels = getAllNovels();  
  7.         for (String novel : allNovels) {  
  8.             browseCount += getBrowseCount(novel);  
  9.         }  
  10.         return browseCount;  
  11.     }  
  12.   
  13.     @Override  
  14.     public int getSalesCount() {  
  15.         int saleCount = 0;  
  16.         List<String> allNovels = getAllNovels();  
  17.         for (String novel : allNovels) {  
  18.             saleCount += getSaleCount(novel);  
  19.         }  
  20.         return saleCount;  
  21.     }  
  22.   
  23. }  

在这两个方法中分别统计了小说类书籍的浏览量和销售量。那么同样的方法,你的leader又定义了一个ComputerBookStatistics类用于统计计算机类书籍的浏览量和销售量:

[java] view plain copy
 
  1. public class ComputerBookStatistics implements Statistics {  
  2.   
  3.     @Override  
  4.     public int getBrowseCount() {  
  5.         int browseCount = 0;  
  6.         List<String> allComputerBooks = getAllComputerBooks();  
  7.         for (String computerBook : allComputerBooks) {  
  8.             browseCount += getBrowseCount(computerBook);  
  9.         }  
  10.         return browseCount;  
  11.     }  
  12.   
  13.     @Override  
  14.     public int getSalesCount() {  
  15.         int saleCount = 0;  
  16.         List<String> allComputerBooks = getAllComputerBooks();  
  17.         for (String computerBook : allComputerBooks) {  
  18.             saleCount += getSaleCount(computerBook);  
  19.         }  
  20.         return saleCount;  
  21.     }  
  22.   
  23. }  

这样将具体的统计实现分散在各个类中,就不会再出现你刚刚那种方法爆炸的情况了。不过这还没开始真正使用组合模式呢,好戏还在后头,你的leader吹嘘道。

 

再定义一个MedicalBookStatistics类实现了Statistics接口,用于统计医学类书籍的浏览量和销售量,代码如下如示:

[java] view plain copy
 
  1. public class MedicalBookStatistics implements Statistics {  
  2.   
  3.     @Override  
  4.     public int getBrowseCount() {  
  5.         int browseCount = 0;  
  6.         List<String> allMedicalBooks = getAllMedicalBooks();  
  7.         for (String medicalBook : allMedicalBooks) {  
  8.             browseCount += getBrowseCount(medicalBook);  
  9.         }  
  10.         return browseCount;  
  11.     }  
  12.   
  13.     @Override  
  14.     public int getSalesCount() {  
  15.         int saleCount = 0;  
  16.         List<String> allMedicalBooks = getAllMedicalBooks();  
  17.         for (String medicalBook : allMedicalBooks) {  
  18.             saleCount += getSaleCount(medicalBook);  
  19.         }  
  20.         return saleCount;  
  21.     }  
  22.   
  23. }  

不知道你发现了没有,计算机类书籍和医学类书籍其实都算是科技类书籍,它们是可以组合在一起的。这个时候你的leader定义了一个TechnicalStatistics类用于对科技这一组合类书籍进行统计:

[java] view plain copy
 
  1. public class TechnicalStatistics implements Statistics {  
  2.       
  3.     private List<Statistics> statistics = new ArrayList<Statistics>();  
  4.       
  5.     public TechnicalStatistics() {  
  6.         statistics.add(new ComputerBookStatistics());  
  7.         statistics.add(new MedicalBookStatistics());  
  8.     }  
  9.   
  10.     @Override  
  11.     public int getBrowseCount() {  
  12.         int browseCount = 0;  
  13.         for (Statistics s : statistics) {  
  14.             browseCount += s.getBrowseCount();  
  15.         }  
  16.         return browseCount;  
  17.     }  
  18.   
  19.     @Override  
  20.     public int getSalesCount() {  
  21.         int saleCount = 0;  
  22.         for (Statistics s : statistics) {  
  23.             saleCount += s.getBrowseCount();  
  24.         }  
  25.         return saleCount;  
  26.     }  
  27.   
  28. }  

可以看到,由于这个类是组合类,和前面几个类还是有不少区别的。首先TechnicalStatistics中有一个构造函数,在构造函数中将计算机类书籍和医学类书籍作为子分类添加到statistics列表当中,然后分别在getBrowseCount和getSalesCount方法中遍历所有的子分类,计算出它们各自的浏览量和销售量,然后相加得到总额返回。

 

组合模式的扩展性非常好,没有各种条条框框,想怎么组合就怎么组合,比如所有书籍就是由各个分类组合而来的,你的leader马上又向你炫耀了统计所有书籍的浏览量和销售量的办法。

 

定义一个AllStatistics类实现了Statistics接口,具体代码如下所示:

[java] view plain copy
 
  1. public class AllStatistics implements Statistics {  
  2.   
  3.     private List<Statistics> statistics = new ArrayList<Statistics>();  
  4.   
  5.     public AllStatistics() {  
  6.         statistics.add(new NovelStatistics());  
  7.         statistics.add(new TechnicalStatistics());  
  8.     }  
  9.   
  10.     @Override  
  11.     public int getBrowseCount() {  
  12.         int browseCount = 0;  
  13.         for (Statistics s : statistics) {  
  14.             browseCount += s.getBrowseCount();  
  15.         }  
  16.         return browseCount;  
  17.     }  
  18.   
  19.     @Override  
  20.     public int getSalesCount() {  
  21.         int saleCount = 0;  
  22.         for (Statistics s : statistics) {  
  23.             saleCount += s.getBrowseCount();  
  24.         }  
  25.         return saleCount;  
  26.     }  
  27.   
  28. }  

在AllStatistics的构造函数中将小说类书籍和科技类书籍作为子分类添加到了statistics列表当中,目前你也就只写好了这几个分类。然后使用同样的方法在getBrowseCount和getSalesCount方法中统计出所有书籍的浏览量和销售量。

 

当前组合结构的示意图如下:

技术分享图片

 

现在你就可以非常方便的得到任何分类书籍的浏览量和销售量了,比如说获取科技类书籍的浏览量,你只需要调用:

[java] view plain copy
 
  1. new TechnicalStatistics().getBrowseCount();  

而获取所有书籍的总销量,你只需要调用:

[java] view plain copy
 
  1. new AllStatistics().getSalesCount();  

当然你后面还可以对这个组合结构随意地改变,添加各种子分类书籍,而且子分类的层次结构可以任意深,正如前面所说,组合模式的扩展性非常好。

 

你的leader告诉你,目前他写的这份代码重复度比较高,其实还可以好好优化一下的,把冗余代码都去除掉。当然这个任务就交给你来做了,你的leader可是大忙人,早就一溜烟跑开了。

 

组合:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

 

以上是关于在java里Composite是啥的主要内容,如果未能解决你的问题,请参考以下文章

组合模式-Composite(Java实现)

组合模式(Composite)

hibernate里联合主键composite-id映射,查询单个主键的问题

聊聊 C# 中的 Composite 模式

设计模式:Composite模式

九 合成(Composite)模式 --结构模式(Structural Pattern)