习惯从一个例子入手。我边写边做这个例子。
假如说现在有这样子的需求,让你模仿系统的个人文件夹做一个应用。说白了让你做个资源管理的东东。给个例子如下图:
做一个应用起头应该想一下怎么把这个需求抽象出一个一个的模型。看下这个发现有点像树这种数据结构,那的确是树。
怎么表示一棵树?
你写过没?我写过N
多次了,学习数据结构的时候经常写到二叉树,但是这次不是二叉,所以还是有点不同,我是这么写。
首先是有结点类,表示每一个结点。
public class Node {
private String name;
private ArrayList<Node> sons;
public Node(String name) {// 构造方法让sons初始化
this.name = name;
sons = new ArrayList<Node>();
}
public void display() {// 打印结点的名字
System.out.println(name);
}
public void addSon(Node son) {// 添加一个结点
sons.add(son);
}
public void traverse() {// 遍历该节点下面的文件夹和文件
for (Node son : sons) {
System.out.println(son.getName());
if (son.getSons().size() != 0) {// 如果不是叶子结点,还得继续追下去
son.traverse();
}
}
}
//各种setters()和getters()。 <!-- [if gte mso 9]><xml>
接下来是树类。
public class Tree {
private Node root;
public Tree(Node root) {
this.root = root;
}
public void traverse() {
root.traverse();
}
}
接下来是场景。如下:
public class Client {
public static void main(String[] args) {
Node root = new Node("个人文件夹");
Tree userProfile = new Tree(root);
// 下面是组装的过程
// 定义第一级子目录,然后给根节点
Node document = new Node("文档");
Node collection = new Node("收藏");
Node music = new Node("音乐");
Node readme = new Node("readme.txt");
root.addSon(music);
root.addSon(document);
root.addSon(collection);
root.addSon(readme);
// 给“文档”添加子目录和文件
Node log = new Node("日志");
Node data = new Node("资料");
Node work = new Node("工作");
document.addSon(log);
document.addSon(data);
document.addSon(work);
// 给“收藏”添加子目录和文件
collection.addSon(new Node("火狐收藏"));
collection.addSon(new Node("http://jason61719.iteye.com"));
// 给“日志”添加文件
log.addSon(new Node("04.17.txt"));
log.addSon(new Node("04.18.txt"));
log.addSon(new Node("04.19.txt"));
// 现在让他们打印出来
userProfile.traverse();
}
}
结果:
音乐
文档
日志
04.17.txt
04.18.txt
04.19.txt
资料
工作
收藏
火狐收藏
http://jason61719.iteye.com
readme.txt
一切正常。如果说这个就是组合模式你信不信?我不信。难道我随手一写就是个模式?事实上,这个真的不是。不过组合模式中有一种叫“透明的组合模式”跟这个就有点类似。
说回来,其实我们用Node
这个类去表示folder
(文件夹)和file
(文件)这两种类型,但实际上只是因为我们的业务很简单,如果系统还要求file
必须记录扩展名,用户,修改时间,大小,编码格式等等,这些都是folder
没有的,这时候还用一个类去表示这2
个完全不同的模型,那就太不应该了,模型设计完以后还得考虑数据存储,如果用一个类去表示这2
个模型,那么数据库的冗余字段就太多了!所以应该设计多个类。
要遵循面向接口编程的原则,为了方便给上层调用,统一一个接口。实际上在这里接口并不好用,有些方法是一样的,属性是一样的,如果用抽象类那是更好的选择。如下代码:
//抽象类,抽象出文件和文件夹
public abstract class AbstractFile {
protected String name;
public AbstractFile(String name) {
this.name = name;
}
public void display() {
System.out.println(name);
}
public abstract void traverse();
}
// 具体的实现类文件夹
public class Folder extends AbstractFile {
private ArrayList<AbstractFile> sons;
public Folder(String name) {
super(name);
sons = new ArrayList<AbstractFile>();
}
public void addSon(AbstractFile son) {
sons.add(son);
}
@Override
public void traverse() {
for (AbstractFile son : sons) {
if (son instanceof File) {
System.out.println("fileName\t\t" + son.name);
} else {
System.out.println("folderName\t" + son.name);
son.traverse();
}
}
}
}
//具体的实现类文件
public class File extends AbstractFile {
private String expandName;// 扩展名
private Integer size;// 大小
public File(String name) {
super(name);
}
@Override
public void traverse() {
System.out.println("fileName\t\t" + name);
}
//各种getters和setters
}
//场景
public static void main(String[] args) {
Folder root = new Folder("个人文件夹");
// 下面是组装的过程
// 定义第一级子目录,然后给根节点
Folder document = new Folder("文档");
Folder collection = new Folder("收藏");
Folder music = new Folder("音乐");
File readme = new File("readme.txt");
root.addSon(music);
root.addSon(document);
root.addSon(collection);
root.addSon(readme);
// 给“文档”添加子目录和文件
Folder log = new Folder("日志");
Folder data = new Folder("资料");
Folder work = new Folder("工作");
document.addSon(log);
document.addSon(data);
document.addSon(work);
// 给“收藏”添加子目录和文件
collection.addSon(new File("火狐收藏"));
collection.addSon(new File("http://jason61719.iteye.com"));
// 给“日志”添加文件
log.addSon(new File("04.17.txt"));
log.addSon(new File("04.18.txt"));
log.addSon(new File("04.19.txt"));
// 现在让他们打印出来
root.traverse();
}
好吧接下来该解说一下了。
组合模式跟普通的处理类之间关系的模式不大一样,事实上是用来描述一种特殊的类组合的关系。UML
里面的组合关系就是指一种比聚合依赖和关联都强的关系,是一种has-a
的关系。这几个关系表现在代码是一样的,不过在数据库的存储就不一样。算是有限制条件的存储。不说这个,我主要是想说明组合关系是has-a
关系。组合关系不仅是has-a
,而且是contains-a
,就是说是描述部分和整体关系的。在代码中经常的体现就是部分类以一个List
或者数组的形式出现在整体类中,如上例子中Folder
中有ArrayList<AbstractFile>
。
如果我们用一个类来表示这整个资源管理的模型,显然是不靠谱。首先这个资源是有深度的,而且深度不确定,第二是这个资源类别有很多种,还有很多原因。
这时候我们应该用组合模式来描述这种组合关系。为什么呢?先说说组合模式的定义和它的几个特点。
定义:将对象以树形结构组织起来,
以达成“
部分-整体”
的层次结构,使得客户端对单个对象和组合对象的使用具有一致性.
这在上面就表现为客户端不必关心自己处理的是单个对象还是组合结构,他们看见的都是一个接口或者抽象类。
优点:高层模块的调用变得简单;节点的增加变得自由
缺点:在封装的过程要声明这是叶节点还是分支,所以这是不符合面向接口编程的。
参考:《设计模式之禅》
分享到:
相关推荐
c++设计模式-结构型模式-组合模式;qt工程;c++简单源码; 组合(Composite Pattern)模式的定义:有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系...
在本文中,我们将深入探讨结构型设计模式,特别是桥接模式、适配器模式、装饰者模式和组合模式,以及它们在实际场景中的应用。 1. **桥接模式**: 桥接模式将抽象部分与实现部分分离,使得它们可以独立进行变化。...
标题中的“C#面向对象设计模式纵横谈(9):Composite组合模式(结构型模式)”明确了文章的主题聚焦于C#语言环境下的设计模式探讨,具体到第9篇讨论的是“Composite组合模式”。这一模式属于结构型模式的一种,旨在解决...
JAVA-设计模式-结构型模式-组合模式
组合模式是一种结构型设计模式,它允许我们以统一的方式处理单个对象和对象的集合,也就是部分与整体的关系。在软件工程中,这种模式经常用于表示具有层次结构的数据,如文件系统、组织结构或者HTML文档的元素结构。...
组合模式是软件设计模式中的一种,属于结构型设计模式。其核心思想是将对象组合成树形结构以表示部分-整体的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性。 ### 组合模式定义 组合模式允许将...
这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。 我们通过下面的实例来演示组合模式的用法。实例演示了一个组织中员工的...
组合模式是一种结构型设计模式,它允许我们以统一的方式处理单个对象和对象的集合,实现了部分与整体的层次结构。这种模式将对象组织成树形结构,使得客户端可以一致地处理单个对象和对象组合,即“部分-整体”的...
5. **组合模式**:将对象组织成树形结构,允许客户以一致方式处理单个对象和对象集合。 6. **外观模式**:提供一个统一的接口,简化子系统的访问,降低客户端与子系统的耦合。 7. **享元模式**:通过共享技术,有效...
在给定的压缩包文件中,我们关注的是结构型设计模式,这些模式主要用于处理类和对象的组合与结构,以实现更灵活、可扩展的设计。下面我们将详细探讨其中涉及到的几个模式:桥接模式、适配器模式、装饰者模式和组合...
组合模式是一种对象结构型设计模式,它允许我们创建表示部分-整体层次结构的树形对象。在空军指挥系统中,这种模式的应用可以帮助我们构建一个灵活、可扩展的组织架构,其中每个部分(如飞机、飞行编队或基地)都...
组合模式:用组合模式显示其所选商品信息,并计算所选商品总价的功能。说明:假如王同学到万达生活用品店购物。用 1 个红色小袋子装了 2 包衡阳特产(单价 25 元)、1 张衡阳地图(单价5.8元).....5.享元模式:在...
组合模式作为一种强大的设计模式,通过将对象组合成树形结构,可以表示“部分-整体”的层次结构,并统一地处理单个对象和组合对象,简化了客户端代码的复杂性,从而提高代码的灵活性和可扩展性。在实际开发中,它在...
组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构以表示“部分-整体”的层次结构。这种模式使得客户端可以统一对待单个对象和对象组合。在组合模式中,有两种基本类型的对象:叶...
结构型模式主要关注如何将类或对象组合成更大的结构。这类模式强调的是如何构建与组织类和对象,以便于形成更复杂的架构。结构型模式包括但不限于外观模式、代理模式、适配器模式、桥接模式等。 #### 三、外观模式 ...
结构型模式是指在软件设计中,如何将类组合在一起去构成更大的结构的模式。它主要解决了类之间的组合问题,包括适配器、桥接、组合、装饰、外观、飞weight和代理等七种模式。 行为型模式是指在软件设计中,如何定义...