Android源码设计模式学习笔记-组合模式

组合模式也是结构模式之一,组合模式比较简单,它将一组相似的对象看作一个对象处理,并根据一个树状结构来组合对象,然后提供一个统一的方法去访问相应的对象,以此忽略掉对象与对象之间的差别。它的UML图如下

Android源码设计模式学习笔记-组合模式
文章图片
image.png
下面是它的模版代码

public abstract class Component { protected String name; public Component(String name) { this.name = name; }/** * 具体逻辑的方法由子类实现 */ public abstract void doSomething(); }

public class Composite extends Component{/** * 存储节点的容器 * @param name */ private List components = new ArrayList<>(); public Composite(String name) { super(name); }@Override public void doSomething() { System.out.println(name); if (null != components){ for (Component c : components){ c.doSomething(); } } }/** * 添加子节点 * @param child */ public void addChild(Component child){ components.add(child); }/** * 移除子节点 * @param child */ public void removeChild(Component child){ components.remove(child); }/** * 获取子节点 * @param index * @return */ public Component getChildren(int index){ return components.get(index); } }

public class Leaf extends Component{public Leaf(String name) { super(name); }@Override public void doSomething() { System.out.print(name); } }

public class Client { public static void main(String[] args){ //构造一个根节点 Composite root = new Composite("Root"); //构造两个枝干节点 Composite branch1 = new Composite("Branch1"); Composite branch2 = new Composite("Branch2"); //构造两个叶子节点 Leaf leaf1 = new Leaf("Leaf1"); Leaf leaf2 = new Leaf("Leaf2"); //将叶子节点添加至枝干节点中 branch1.addChild(leaf1); branch2.addChild(leaf2); //将枝干节点添加至根节点中 root.addChild(branch1); root.addChild(branch2); //执行方法 root.doSomething(); } }

角色介绍:
Component : 抽象根节点,为组合中的对象声明接口。
Composite : 定义有子节点的那些枝干节点的行为,存储子节点,在Component接口中实现与子节点有关的操作
Leaf : 在组合中表示叶子节点对象
Client : 通过Component接口操作组合节点的对象
组合模式的简单实现 下面我们以文件夹系统为例讲解一下组合模式的简单实现,整个文件夹系统如下所示

Android源码设计模式学习笔记-组合模式
文章图片
image.png
首先声明一个抽象类,表示文件或文件夹
public abstract class Dir { /** * 声明一个List成员变量存储文件夹下的所有元素 */ protected List dirs = new ArrayList<>(); private String name; //当前文件夹名public Dir(String name) { this.name = name; }/** * 添加一个文件或文件夹 */ public abstract void addDir(Dir dir); /** * 移除一个文件或文件夹 */ public abstract void rmDir(Dir dir); /** * 清除文件夹下面的所有元素 */ public abstract void clear(); /** * 清空文件夹下的所有元素 */ public abstract void print(); /** * 获取文件夹下所有的文件或子文件夹 */ public abstract List getFiles(); /** * 获取文件或文件夹名 */ public String getName(){ return name; } }

public class File extends Dir{ public File(String name) { super(name); }@Override public void addDir(Dir dir) {}@Override public void rmDir(Dir dir) {}@Override public void clear() {}@Override public void print() {}@Override public List getFiles() { return null; } }

public class Folder extends Dir{ public Folder(String name) { super(name); }@Override public void addDir(Dir dir) { dirs.add(dir); }@Override public void rmDir(Dir dir) { dirs.remove(dir); }@Override public void clear() { dirs.clear(); }@Override public void print() { System.out.print(getName()+"("); Iterator iter = dirs.iterator(); while (iter.hasNext()){ Dir dir = iter.next(); dir.print(); if (iter.hasNext()){ System.out.print(","); } } System.out.print(")"); }@Override public List getFiles() { return dirs; } }

public class Client { public static void main(String[] args){ //构造一个目录对象表示C盘根目录 Dir diskC = new Folder("C"); //C盘根目录下有一个文件ImbaMallLog.txt diskC.addDir(new File("ImbaMallLog.txt")); //C盘目录下还有3个子目录Windows,PrefLogs,Program File Dir dirWin = new Folder("Windows"); //Windows目录下有文件explorer.exe dirWin.addDir(new File("explorer.exe")); diskC.addDir(dirWin); //PerfLogs目录 Dir dirPer = new Folder("PerfLogs"); //PerfLogs目录下有文件null.txt dirPer.addDir(new File("null.txt")); diskC.addDir(dirPer); //Program File 目录 Dir dirPro = new Folder("Program File"); //Program File 目录下有文件ftp.txt dirPro.addDir(new File("ftp.txt")); diskC.addDir(dirPro); //打印出文件结构 diskC.print(); } }

Android源码中的模式实现 在android中View和ViewGroup这种嵌套就是一种组合模式

Android源码设计模式学习笔记-组合模式
文章图片
image.png 为什么ViewGroup有容器的功能 要回答这个问题,就要先了解View类与ViewGroup的差别在哪,首先要知道ViewGroup继承自View类
public abstract class ViewGroup extends View implements ViewParent, ViewManager

【Android源码设计模式学习笔记-组合模式】从继承角度来说ViewGroup拥有View类所有非私有化方法,既然如此,两者差别就在于ViewGroup所实现的ViewParent和ViewManager接口上,而事实也是如此,ViewManager接口定义了addView, removeView等对子视图操作的方法.
public interface ViewManager{ public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view); }

ViewParent则定义了刷新容器的接口requestLayout和其它一些焦点事件的处理的接口.
public interface ViewParent { public void requestLayout(); public boolean isLayoutRequested(); public void requestTransparentRegion(View child); public void invalidateChild(View child, Rect r); public ViewParent invalidateChildInParent(int[] location, Rect r); public ViewParent getParent(); public void requestChildFocus(View child, View focused); }

另外View中比较重要的两个测绘流程的方法onMeasure和onDraw在ViewGroup中都没有被重写,相对于onMeasure方法,在ViewGroup增加了一些计算子view的方法,如measureChildren,measureChildrenWithMargins等,而对于onDraw方法,ViewGroup定义了一个dispatchDraw方法来调用每一个子View的onDraw方法,由此可见,ViewGroup真的像一个容器一样,其职责只是负责对子元素的操作而非具体的个体行为.

    推荐阅读