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

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


Android源码设计模式学习笔记-组合模式_第1张图片
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源码设计模式学习笔记-组合模式_第2张图片
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源码设计模式学习笔记-组合模式_第3张图片
image.png

为什么ViewGroup有容器的功能

要回答这个问题,就要先了解View类与ViewGroup的差别在哪,首先要知道ViewGroup继承自View类

public abstract class ViewGroup extends View implements ViewParent, ViewManager

从继承角度来说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真的像一个容器一样,其职责只是负责对子元素的操作而非具体的个体行为.

你可能感兴趣的:(Android源码设计模式学习笔记-组合模式)