1.组合模式
1.1 定义
将对象组合成树形结构以表示“部分--整体”的层次结构,使得用户对单个对象和组合对象使用具有一致性。
1.2 UML
组合模式可以分两种类型:安全的组合模式和透明的组合模式。主要区别根节点和子节点的结构是完全一致的。

安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的。叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供add()、remove()以及getChild()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)。
- Component:抽象根节点,是组合中的对象声明接口
- Composite:定义子节点的哪些枝干点的行为,存储子节点,在component接口中实现与子节点有关的操作。
- Leaf:在组合中表示子节点对象,叶子节点没有子节点,在组合中定义节点对象的行为
- Client:通过component接口操作组合节点对象的行为
1.3 使用场景
- 表示对象的部分--整体层次结构
- 从一个整体中能够独立出部分模块或功能场景
1.4 代码的实现
我们以文件杀毒为例:我们可以把杀毒这个功能抽象出来。子节点我们可以对文件,视频,图片进行杀毒,也可以对文件夹进行杀毒。其中文件夹可能包含上述所有的。
A.安全的组合模式
//抽象构建
public interface AbstractFile {
void killVirus(); //杀毒
}
//图片
class ImageFile implements AbstractFile {
private String name;
public ImageFile(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---图像文件:"+name+",进行查杀!");
}
}
//文件
class TextFile implements AbstractFile {
private String name;
public TextFile(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---文本文件:"+name+",进行查杀!");
}
}
//视频
class VideoFile implements AbstractFile {
private String name;
public VideoFile(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---视频文件:"+name+",进行查杀!");
}
}
//文件夹
class Folder implements AbstractFile {
private String name;
//定义容器,用来存放本容器构建下的子节点
private List<AbstractFile> list = new ArrayList<AbstractFile>();
public Folder(String name) {
super();
this.name = name;
}
public void add(AbstractFile file){
list.add(file);
}
public void remove(AbstractFile file){
list.remove(file);
}
public AbstractFile getChild(int index){
return list.get(index);
}
@Override
public void killVirus() {
System.out.println("---文件夹:"+name+",进行查杀");
for (AbstractFile file : list) {
file.killVirus();
}
}
}
调用方式:

B.透明的组合模式
//抽象构建
public interface AbstractFileTM {
void killVirus(); //杀毒
void add(AbstractFileTM file);
void remove(AbstractFileTM file);
AbstractFileTM getChild(int index);
}
class ImageFileTM implements AbstractFileTM {
private String name;
public ImageFileTM(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---图像文件:"+name+",进行查杀!");
}
@Override
public void add(AbstractFileTM file) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
@Override
public void remove(AbstractFileTM file) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
@Override
public AbstractFileTM getChild(int index) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
}
class TextFileTM implements AbstractFileTM {
private String name;
public TextFileTM(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---文本文件:"+name+",进行查杀!");
}
@Override
public void add(AbstractFileTM file) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
@Override
public void remove(AbstractFileTM file) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
@Override
public AbstractFileTM getChild(int index) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
}
class VideoFileTM implements AbstractFileTM {
private String name;
public VideoFileTM(String name) {
super();
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---视频文件:"+name+",进行查杀!");
}
@Override
public void add(AbstractFileTM file) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
@Override
public void remove(AbstractFileTM file) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
@Override
public AbstractFileTM getChild(int index) {
throw new UnsupportedOperationException("叶子节点没有子节点");
}
}
class FolderTM implements AbstractFileTM {
private String name;
//定义容器,用来存放本容器构建下的子节点
private List<AbstractFileTM> list = new ArrayList<AbstractFileTM>();
public FolderTM(String name) {
super();
this.name = name;
}
public void add(AbstractFileTM file){
list.add(file);
}
public void remove(AbstractFileTM file){
list.remove(file);
}
public AbstractFileTM getChild(int index){
return list.get(index);
}
@Override
public void killVirus() {
System.out.println("---文件夹:"+name+",进行查杀");
for (AbstractFileTM file : list) {
file.killVirus();
}
}
}
调用方式:

1.5 优缺点
优点
- 不破坏封装,整体类与局部类之间松耦合,彼此相对独立 。
- 具有较好的可扩展性。
- 支持动态组合。在运行时,整体对象可以选择不同类型的局部对象。
- 整体类可以对局部类进行包装,封装局部类的接口,提供新的接口。
缺点
- 创建整体类的对象时,需要创建所有局部类的对象 。
1.6 android源码中的实现
View和viewgroup之间的组合关系

ViewGroup和View的区别:
-
ViewGroup继承了view实现了ViewParent, ViewManager接口
ViewManger
-
ViewGroup是抽象类将View中的onLayout方法重置为抽象方法,也就是说容器子类必须实现该方法来实现布局的定位,在view中该方法是空实现,因为对一个普通View来说并没有实现的价值,在ViewGroup中必须实现。
-
View中onMeasure和onDraw在ViewGroup中都没有被重写。相当于onMeasure在viewgroup中添加了一些计算子view的方法,如measureChildren,measureChildrenWithMargins。相当于onDraw方法,ViewGroup定义了一个dispatchDraw方法来调用其每一个子View的onDraw方法。
2.适配器模式
2.1 定义
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原来因接口不匹配而无法在一起工作的两个类能在一起工作。
2.2 UML
适配器模式分:A.类适配B.对象适配

- Target:目标角色,也就是所期望得到的接口。
- Adaptee:现在需要适配的接口。
- Adapter:适配器角色,把源接口转换成目标接口。
区别:
- 对象适配器模式直接将要的适配的对象传递到adapter中,使用组合的形式实现接口的兼容的效果。
- 被适配的对象中的方法不会暴露出来,而类适配器由于继承了适配的对象。因此,被适配对象 类的函数在adapter类中也都含有,这使得adapter类出现一些奇怪的接口。用户使用成本高。
2.3 使用场景
- 系统需要使用现有的类,而次类的接口不符合系统的需求,接口不兼容。
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
- 需要一个统一的输出接口,而输入端的类型不可预知
2.4 代码实现
A. Target目标角色
public interface Target {
void handleReq();
}
B.Adaptee实现的接口
public class Adaptee {
public void request(){
System.out.println("可以完成客户请求的需要的功能!");
}
}
C.类适配器
public class Adapter extends Adaptee implements Target {
@Override
public void handleReq() {
super.request();
}
}
D.对象适配器
public class Adapter2 implements Target {
private Adaptee adaptee;
@Override
public void handleReq() {
adaptee.request();
}
public Adapter2(Adaptee adaptee) {
super();
this.adaptee = adaptee;
}
}
E.调用
public class Client {
public void test1(Target t){
t.handleReq();
}
public static void main(String[] args) {
Client c = new Client();
Adaptee a = new Adaptee();
Target t = new Adapter();
Target t2 = new Adapter2(a);
c.test1(t);
}
}
2.5 优缺点
- 优点
复用性好
扩展性好 - 缺点
过多的使用会让系统更加的混乱
2.6 android源码中的使用

从右往左看,假设对与不同类型的Layout以及不同格式的数据,通过一个Adapter适配成为一个ViewHolder,ViewHolder中缓存有每个用于显示的ItemView。ItemView的布局操作则交给了LanyoutManager来管理,ItemView可以根据LayoutManager中的布局策略,完成自己的布局操作,如果不想用系统提供的那三种LayoutManager,完全可以自己根据需求来定制一个,通过Adapter和LayoutManger,整个RecyclerView的功能变得十分强大,可定制性超级高。
网友评论