Android源码中的组合模式
来源:互联网 发布:知乎恐怖提问 编辑:程序博客网 时间:2024/06/07 22:47
从装饰者模式到Context类族
当观察者模式和回调机制遇上Android源码
Android源码中的静态工厂方法
Android中的工厂方法模式
Android源码中的命令模式
Android源码中的适配器模式
Android源码中的外观模式
不只是迭代器模式
定义
允许将对象组成树形结构来表现“整体-部分”的层次结构。组合能让客户以一致的方式处理个别对象和对象组合。属于结构型设计模式。
使用场景
需要表示一个对象整体或部分层次,在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,可以一致地对待它们。
让客户能够忽略不同对象层次的变化,客户端可以针对抽象构件编程,无须关心对象层次结构的细节。
结构
模式所涉及的角色有:
抽象构件角色(component):是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
这个接口可以用来管理所有的子对象。(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
树叶构件角色(Leaf):在组合树中表示叶节点对象,叶节点没有子节点。并在组合中定义图元对象的行为。
树枝构件角色(Composite):定义有子部件的那些部件的行为。存储子部件。在Component接口中实现与子部件有关的操作。
客户角色(Client):通过component接口操纵组合部件的对象。
实现
通过前边的使用场景说明,我们发现文件结构正好就是一个整体-部分层次的树形结构。那如果我们想知道文件名,我们好像并不需要管他是文件还是文件夹,所以我们要想办法忽略不同层次对象的差异。接下来我们看下实现:
抽象构件角色,即文件类的抽象接口
/** * 文件抽象类 */public abstract class File { private String name; public File(String name) { this.name = name; } //操作方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract void watch(); //组合方法 public void add(File file) { throw new UnsupportedOperationException(); } public void remove(File file) { throw new UnsupportedOperationException(); } public File getChild(int position) { throw new UnsupportedOperationException(); }}
树叶构件角色,即我们的具体格式文件,比如文本文件
/** * 文本文件 */public class TextFile extends File { public TextFile(String name) { super(name); } @Override public void watch() { Log.e("组合模式", "这是一个叫" + getName() + "文本文件"); }}
树枝构件角色,即我们的文件夹
/** * 文件夹类 */public class Folder extends File { private List<File> mFileList; public Folder(String name) { super(name); mFileList = new ArrayList<>(); } @Override public void watch() { StringBuffer fileName = new StringBuffer(); for (File file : mFileList) { fileName.append(file.getName() + ";"); } Log.e("组合模式", "这是一个叫" + getName() + "文件夹,包含" + mFileList.size() + "个文件,分别是:" + fileName); } @Override public void add(File file) { mFileList.add(file); } @Override public void remove(File file) { mFileList.remove(file); } @Override public File getChild(int position) { return mFileList.get(position); }}
客户端
/** * 测试组合模式 */private void testComposite() { TextFile textFileA = new TextFile("a.txt"); TextFile textFileB = new TextFile("b.txt"); TextFile textFileC = new TextFile("c.txt"); textFileA.watch();// textFileA.add(textFileB);//调用会抛我们在抽象接口中写的异常 Folder folder = new Folder("学习资料"); folder.add(textFileA); folder.add(textFileB); folder.add(textFileC); folder.watch(); folder.getChild(1).watch();}
这里有一点是我们的抽象构件中包含组合方法和操作方法,有一些操作方法是树叶构件和树枝构件都会实现的,而组合方法是需要树枝构件来实现的,即我们对树叶构件的增删等操作。
Android源码中的组合模式
接下来我们思考一下Android源码中组合模式的应用,组合模式的使用场景是:表示一个对象整体-部分层次结构,即树形结构。而Android中典型的树形结构不就是我们的View体系么。在前边的模板方法模式中我们已经画过view的结构了,这里就不再画了,我们来一起分析一下:
Android源码中View是一个类(不是抽象类,不是接口),即我们的抽象构件。ViewGroup是View的子类,是一个抽象类,作为所有View的容器,即我们的树枝构件。而具体到特定的控件,比如Button、TextView等是我们的树叶构件。
通过观察我们的View类中是没有封装添加删除View的操作的,那么它们是在哪里添加到ViewGroup中的呢?我们发现ViewGroup实现了一个叫ViewManager的接口:
/** Interface to let you add and remove child views to an Activity. To get an instance * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. */public interface ViewManager{ /** * Assign the passed LayoutParams to the passed View and add the view to the window. * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming * errors, such as adding a second view to a window without removing the first view. * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a * secondary {@link Display} and the specified display can't be found * (see {@link android.app.Presentation}). * @param view The view to be added to this window. * @param params The LayoutParams to assign to view. */ public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view);}
ViewGroup实现这个接口的方法,所有就有了管理View的能力。
那么Google的开发者为什么要这么设计Android的View体系呢?组合模式可以让高层模块忽略了层次的差异,方便对整个层次结构进行控制。比如我们要向ViewGoup添加一个TextView或者添加一个LinearLayout,对这个ViewGroup来说是一样的。
搞定,收工。
测试代码已上传到github。
- Android源码中的组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android设计模式系列(1)--SDK源码之组合模式
- Android 源码中的设计模式
- Android源码中的适配器模式
- Android 源码中的设计模式
- Android 源码中的设计模式
- Android源码中的观察者模式
- Android源码中的命令模式
- Android源码中的适配器模式
- Android源码中的外观模式
- bzoj 2791 [Poi2012]Rendezvous 倍增lca 基环树
- Discarding record on action DISCARD on error 1403
- json数据表单回填
- VB里面的Line方法的具体使用方法
- DevExpress ComboBoxEdit List绑定二级选择下拉表
- Android源码中的组合模式
- LeetCode No.120 Triangle
- Uiautomator之python封装包安装
- 一步一步用 java 设计生成二维码
- c#用IMessageFilter拦截键盘消息
- android事件分发机制的再学习
- 对 caffe 中Xavier, msra 权值初始化方式的解释
- mongo db(用 mongo VUE windows) 仅查询某个字段且不为空的所有值
- php下POST json数据无法解析问题