简介
将对象组合成树形结构以表示部分-整体的层次结构,使客户端对单个对象和组合对象保持一致的方式处理,如果你要处理树形结构的数据时,程序总是会写的很复杂,你必须要区分哪个是叶子节点,哪个是分支,使用组合模式,可以简化复杂,让程序更容易扩展。定义一个统一的Component接口,所有组合模式的类都实现该接口
,Leaf对象直接实现Component接口,Composite对象将请求转发给其子组件,该模式
属于结构型。
树形如图:
适用场景
1、希望客户端忽略组合对象与单个对象的差异时
2、处理一个树形结构时
优点
1、清楚的定义分层次的复杂对象,表示对象的全部或部分层次
2、让客户端忽略了层次的差异,方便对整个层次结构进行控制
3、简化客户端代码
4、符合开闭原则
缺点
1、限制类型时会比较复杂
2、使设计变得更加抽象
代码示例
背景说明:菜谱有目录和具体菜名,目录下面包含一些菜名,菜的话有名称和价格,目录有名称,可以添加、删除某些菜。
目录和菜名的公共抽象类
public abstract class CatalogComponent {
public String getName(CatalogComponent catalogComponent){
throw new UnsupportedOperationException("不支持获取名称");
}
public void add(CatalogComponent catalogComponent){
throw new UnsupportedOperationException("不支持添加");
}
public void remove(CatalogComponent catalogComponent){
throw new UnsupportedOperationException("不支持移除");
}
public double getPrice(CatalogComponent catalogComponent){
throw new UnsupportedOperationException("不支持获取价格");
}
public void show(){
throw new UnsupportedOperationException("不支持展示");
}
}
食物类,继承了CatalogComponent对象
public class Food extends CatalogComponent {
private String name;
private double price;
public Food(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String getName(CatalogComponent catalogComponent) {
return this.name;
}
@Override
public double getPrice(CatalogComponent catalogComponent) {
return this.price;
}
@Override
public void show() {
System.out.println("食物名称:"+this.name+";价格"+this.price);
}
}
菜谱目录类,也继承了CatalogComponent类
public class MenuCatalog extends CatalogComponent{
private String name;
private List<CatalogComponent> items = new ArrayList<CatalogComponent>();
public MenuCatalog(String name) {
this.name = name;
}
@Override
public String getName(CatalogComponent catalogComponent) {
return this.name;
}
@Override
public void add(CatalogComponent catalogComponent) {
items.add(catalogComponent);
}
@Override
public void remove(CatalogComponent catalogComponent) {
items.remove(catalogComponent);
}
@Override
public void show() {
System.out.println("菜单目录:"+this.name);
for(CatalogComponent catalogComponent : items){
catalogComponent.show();
}
}
}
测试类
public class CompositeTest {
public static void main(String[] args) {
CatalogComponent food = new Food("红烧肉",20);
CatalogComponent food2 = new Food("红烧鸡",15);
CatalogComponent meatCatalog = new MenuCatalog("荤菜系列");
meatCatalog.add(food);
meatCatalog.add(food2);
CatalogComponent food3 = new Food("炒青菜",2);
CatalogComponent food4 = new Food("干锅花菜",3);
CatalogComponent soupCatalog = new MenuCatalog("蔬菜系列");
soupCatalog.add(food3);
soupCatalog.add(food4);
CatalogComponent mainCatalog = new MenuCatalog("主菜单目录");
mainCatalog.add(meatCatalog);
mainCatalog.add(soupCatalog);
mainCatalog.show();
}
}
输出结果
菜单目录:主菜单目录
菜单目录:荤菜系列
食物名称:红烧肉;价格20.0
食物名称:红烧鸡;价格15.0
菜单目录:蔬菜系列
食物名称:炒青菜;价格2.0
食物名称:干锅花菜;价格3.0
源码分析
jdk中应用
HashMap继承了Map接口
public void putAll(Map<? extends K, ? extends V> m) {
putMapEntries(m, true);
}
该方法的入参是map,跟示例中的add是一样的。
ArrayList中的addAll方法,也是一样的。
mybatis中应用
SqlNode是组合模式比较好的体现,如子类MixedSqlNode:
public class MixedSqlNode implements SqlNode {
private List<SqlNode> contents;
public MixedSqlNode(List<SqlNode> contents) {
this.contents = contents;
}
@Override
public boolean apply(DynamicContext context) {
for (SqlNode sqlNode : contents) {
sqlNode.apply(context);
}
return true;
}
}
部分子类的UML类图
本文为博主原创文章,未经博主允许不得转载。
更多内容请访问:IT源点
注意:本文归作者所有,未经作者允许,不得转载