定义
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性
释义:
- 该模式属于结构型模式,主要用于处理对象与对象之间的包含关系和分层关系,比如文件系统,XML文件等
- 单个对象与组合对象的使用一致性表示需要抽象出其相同的地方,比如文件系统中文件和目录都具有文字,是否隐藏,权限控制等。
角色介绍:
- Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component
子部件。 - Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。
- Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除
(remove)等。
实现
本次实现我们参照Android中View架构设计一个针对图片编辑的框架,比如添加/删除文字,添加/删除贴纸等
public abstract class Element {
Rect mLayout;
Element mParent;
Element mFocusElement;
public abstract void draw(Canvas canvas);
public abstract void move(int x, int y);
public abstract boolean onTouchEvent(MotionEvent motionEvent);
public Element getParent(){
return mParent;
}
public Element getFocusElement(){
return mFocusElement;
}
}
public class StickerElemet extends Element {
@Override
public void draw(Canvas canvas) {
}
@Override
public void move(int x, int y) {
}
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
return false;
}
}
public class TextElement extends Element {
@Override
public void draw(Canvas canvas) {
}
@Override
public void move(int x, int y) {
}
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
return false;
}
}
Element是所有元素的顶级抽象,TextElement和StickerElement是单个元素的具体实现类,分别表示文本元素和贴纸元素,具体的Element实现者只负责处理自己的绘制和触摸事件等,不能操作其父节点和兄弟节点。
public interface ElementManager {
public void addElement(Element element);
public void removeElement(Element element);
}
ElementManager是元素管理接口,定义了元素的增加和删除接口,其实现类需要实现约定接口功能。
public abstract class ElementGroup extends Element implements ElementManager{
List<Element> mChildren = new ArrayList<>();
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
return false;
}
public abstract boolean onIntercepted(MotionEvent motionEvent);
public abstract boolean dispatchTouchEvent(MotionEvent motionEvent);
public abstract void drawChildren(Canvas canvas);
public abstract Element getChildren(int position);
public abstract void justOrder();
}
ElementGroup是Element的组合对象的抽象类,可以看到其实现ElementManager接口,ElementGroup实现者的职责是管理Element子节点,主要是元素操作(增加,删除,调整zOrder等),事件分发等。
总结
从上述demo可以看出,组合模式对于元素之间的隔离是比较高的,客户端程序不必关心元素具体类型,而且可以动态添加元素和容器。其缺点是在构建组合元素时,很可能会依赖具体的组合元素类型,所以尽可能将组合元素进行抽象,并且独立元素操作接口(增删改查),使客户端面向接口来操作。