java 设计模式:组合模式
1、概念
将对象以树形结构组织起来,以达成“部分-整体”的层次机构,使得客户端对单个对象和组合对象的使用具有一致性。
是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
2、使用场景
部分、整体场景,如树形菜单,文件、文件夹的管理。
- 需要表示一个对象整体或部分层次
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
3、如何使用
树枝和叶子实现统一接口,树枝内部组合该接口。
4、UML结构图分析
5、实际代码分析
例:文件与文件夹的关系
先进行普通的实现方式
//文件类
public class File {
public String name;
public File(String name) {
this.name = name;
}
/**
* 操作方法
* @return
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void watch() {
System.out.println("文件名"+getName()+"文件数目");
}
}
//文件夹类
public class Folder{
public String name;
private List<File> mFileList;
public Folder(String name) {
mFileList = new ArrayList<>();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void watch() {
StringBuilder sb = new StringBuilder();
for(File f:mFileList){
sb.append(f.name);
}
System.out.println("文件名"+getName()+"文件数目"+ mFileList.size()+"名字"+sb.toString());
}
public void add(File file) {
mFileList.add(file);
}
public void remove(File file) {
mFileList.remove(file);
}
public File getChild(int pos) {
return mFileList.get(pos);
}
}
//运行
File file = new File("hehe");
Folder folder = new Folder("heere");
folder.add(file);
folder.watch();
文件和文件夹作为两个类来进行操作,将文件类进行添加文件,但是呢?如果文件夹下添加文件夹该咋办呢?就需要再创建一个list来存放文件夹,这样大家都是节点,为啥搞得这么复杂呢?既然存在上下级节点的问题,咱们就抽象为一个抽象类,用抽象类作为节点,子类就是文件夹和文件。
//将文件与文件夹统一看作是一类节点,做一个抽象类来定义这种节点,然后以其实现类来区分文件与目录,在实现类中分别定义各自的具体实现内容,把组合方法写到这个节点类中
public abstract class File {
public String name;
public File(String name) {
this.name = name;
}
/**
* 操作方法
* @return
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void watch();
/**
* 组合方法
* @param file
*/
public void add(File file){
throw new UnsupportedOperationException();
}
public void remove(File file){
throw new UnsupportedOperationException();
}
public File getChild(int pos){
throw new UnsupportedOperationException();
}
}
public class Folder extends File{
private List<File> mFileList;
public Folder(String name) {
super(name);
mFileList = new ArrayList<>();
}
@Override
public void watch() {
StringBuilder sb = new StringBuilder();
for(File f:mFileList){
sb.append(f.name);
}
System.out.println("文件名"+getName()+"文件数目"+ mFileList.size()+"名字"+sb.toString());
}
@Override
public void add(File file) {
mFileList.add(file);
}
@Override
public void remove(File file) {
mFileList.remove(file);
}
@Override
public File getChild(int pos) {
return mFileList.get(pos);
}
}
public class TestFile extends File {
public TestFile(String name) {
super(name);
}
@Override
public void watch() {
System.out.println("文件名"+getName()+"文件数目");
}
}
//运行
TestFile file = new TestFile("hehe");
Folder folder = new Folder("heere");
folder.add(file);
folder.watch();
folder.getChild(0).watch();
这种组合模式正是应树形结构而生,所以组合模式的使用场景就是出现树形结构的地方。比如:文件目录显示,多及目录呈现等树形结构数据的操作。
安全组合模式(简化)如下code
//将文件与文件夹统一看作是一类节点,做一个抽象类来定义这种节点,然后以其实现类来区分文件与目录,在实现类中分别定义各自的具体实现内容,把组合方法写到这个节点类中
public abstract class File {
public String name;
public File(String name) {
this.name = name;
}
/**
* 操作方法
* @return
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void watch();
}
public class Folder extends File{
private List<File> mFileList;
public Folder(String name) {
super(name);
mFileList = new ArrayList<>();
}
@Override
public void watch() {
StringBuilder sb = new StringBuilder();
for(File f:mFileList){
sb.append(f.name);
}
System.out.println("文件名"+getName()+"文件数目"+ mFileList.size()+"名字"+sb.toString());
}
public void add(File file) {
mFileList.add(file);
}
public void remove(File file) {
mFileList.remove(file);
}
public File getChild(int pos) {
return mFileList.get(pos);
}
}
public class TestFile extends File {
public TestFile(String name) {
super(name);
}
@Override
public void watch() {
System.out.println("文件名"+getName()+"文件数目");
}
}
//运行
TestFile file = new TestFile("hehe");
Folder folder = new Folder("heere");
folder.add(file);
folder.watch();
folder.getChild(0).watch();
安全组合模式分工就很明确了。它还有一个好处就是当我们add/remove的时候,我们能知道具体的类是什么了,而透明组合模式就得在运行时去判断,比较麻烦。
优点:
- 高层模块调用简单
- 节点自由增加
缺点:
- 在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
- 叶子类型不能控制。比如我想控制ViewGroup添加的View必须为TextView的时候,约束起来就很麻烦。特别是类型多的时候。