Android设计模式------数据结构模式

"数据结构"模式

使用场景

常常有一些组件在内部具有特定的数据结构,如果让客户程序依赖这些特定的数据结构,将极大地破坏组件的复用。这时候,将这
些特定数据结构封装在内部,在外部提供统一的接口,来实现与特定数据结构无关的访问,是一种行之有效的解决方案。

典型模式
 

●Composite(组合模式)
●Iterator(迭代器)
●Chain of Resposibility(责任链)

 

Composite 组合模式

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

何时使用: 1、您想表示对象的部分-整体层次结构(树形结构)。 2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。

关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。

应用实例: 1、算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作数、操作符和另一个操作数。 2、在 JAVA AWT 和 SWING 中,对于 Button 和 Checkbox 是树叶,Container 是树枝。

优点: 1、高层模块调用简单。 2、节点自由增加。

缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。

注意事项:定义时为具体类。

这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

使用场景

在软件在某些情况下,客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(而非抽象接口)的变化将引
起客户代码的频繁变化,带来了代码的维护性、扩展性等弊端。


模式定义

将对象组合成树形结构以表示"部分-整体"的层次结构。
Composite使得用户对单个对象和组合对象的使用具有一致性(稳定)。

类图结构

Add()和Remove(),GetChild()放在Component抽象类里面是存在争议的。比如下方代码,我并没有把Add()和Remove()放在父类Component中,而是放在Composite树节点里面。放在父类里面会带来一个弊端,叶子节点Leaf类不能实现Add()和Remove(),如果去实现这两个方法,可以抛出异常说明不支持接口,但是这样毫无意义。或者实现之后做空操作,那还不如不实现。放入Composite类实现,也是有弊端的。使用add()的时候要判断对象类型是否是Component。 

所以现在普遍的做法就是不在Component实现Add()和Remove(),GetChild()。放到Composite树节点里面实现。

代码举例

//业务需求抽象类
public abstract class Component {

    public abstract void process();

}

//树节点
public class Composite extends Component {

    String name;
    Vector<Component> elements;

    public Composite(String s) {
        name = s;
    }

    public void add(Component element) {
        elements.add(element);
    }

    public void remove(Component element) {
        elements.remove(element);
    }

	//递归调用
    @Override
    public void process() {
        //1. 处理当前节点

        //2. 处理叶子节点
        for (Component e : elements) {
            e.process();//多态调用
        }
    }
}

//叶子节点
public class Leaf extends Component {
    String name;

    public Leaf(String s) {
        name = s;
    }

    @Override
    public void process() {
        //处理当前节点
    }
}



public class  ClientApp{
	//如果不用Composite模式 c.process(); 不能这样调用 还需要使用typeOf c.getType 判断 c的类型
	//判断c 是 Leaf 还是 Composite 然后做出相应的处理 使用 Composite模式就免去了 这些操作
    public static void invoke(Component c){
        //...
        c.process();  //多态调用
        //...
    }


    public static void main(String args[]) {

        Composite root=new Composite("root");
        Composite treeNode1=new Composite("treeNode1");
        Composite treeNode2=new Composite("treeNode2");
        Composite treeNode3=new Composite("treeNode3");
        Composite treeNode4=new Composite("treeNode4");
        Leaf leat1=new Leaf("left1");
        Leaf leat2=new Leaf("left2");

        root.add(treeNode1);
        treeNode1.add(treeNode2);
        treeNode2.add(leaf1);

        root.add(treeNode3);
        treeNode3.add(treeNode4);
        treeNode4.add(leaf2);

        invoke(root);
        invoke(leaf2);
        invoke(treeNode3);
    }

}

 

在Android中 组合模式的体现 

 View.java 和 ViewGroup.java的举例

View.java 可以看做是 叶子节点 或者是 Component。而 Composite 树节点 就是 ViewGroup。

在ViewGroup 体现了 Composite设计模式

ViewGroup继承View,所以ViewGroup都是树节点 。

ViewGroup 中的 mChildren 数组 对应 上方代码中的   Vector<Component> elements;

hasFocusable() 对应上方代码中的 process(),addFocusables(),findViewsWithText()也是对应process()

 @Override
    boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
        // This should probably be super.hasFocusable, but that would change
        // behavior. Historically, we have not checked the ancestor views for
        // shouldBlockFocusForTouchscreen() in ViewGroup.hasFocusable.

        // Invisible and gone views are never focusable.

        相当于先处理当前节点的业务逻辑
        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 
            return false;
        }

        // Only use effective focusable value when allowed.
        if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
            return true;
        }
        
        //相当于处理叶子节点的业务逻辑
        // Determine whether we have a focused descendant.
        final int descendantFocusability = getDescendantFocusability();
        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
            return hasFocusableChild(dispatchExplicit);  //使用递归
        }

        return false;
    }

要点总结

     Composite模式采用树形结构来实现普遍存在的对象容器,从而将“一对多”的关系转化为“一对一”的关系,使得客户代码可以一致地(复用)处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器。
     将“客户代码与复杂的对象容器结构’'解耦是Composite的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的内部实现结构——发生依赖,从而更能‘应对变化”。
     Composite模式在具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技巧来改善效率。

 

 

Iterator 迭代器

迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。

迭代器模式属于行为型模式。

介绍

意图:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。

主要解决:不同的方式来遍历整个整合对象。

何时使用:遍历一个聚合对象。

如何解决:把在元素之间游走的责任交给迭代器,而不是聚合对象。

关键代码:定义接口:hasNext, next。

应用实例:JAVA 中的 iterator。

优点: 1、它支持以不同的方式遍历一个聚合对象。 2、迭代器简化了聚合类。 3、在同一个聚合上可以有多个遍历。 4、在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

缺点:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

使用场景: 1、访问一个聚合对象的内容而无须暴露它的内部表示。 2、需要为聚合对象提供多种遍历方式。 3、为遍历不同的聚合结构提供一个统一的接口。

注意事项:迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。

使用场景

在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种‘透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。
使用面向对象技术将这种遍历机制抽象为‘迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。

模式定义

提供一种方法顺序访问一个聚合对象(容器)中的各个元素,而又不暴露(稳定)该对象的内部表示。

类图结构

代码举例

迭代器的使用

package File;
import java.util.Iterator;
import java.util.Vector;

public class  ClientApp{

    public static void main(String args[]) {

        Vector<String> mc=new Vector<>();
        mc.add("Beijing");
        mc.add("Shanghai");
        mc.add("New York");
        mc.add("Paris");
        mc.add("London");


        Iterator<String> iter = mc.iterator();

        while (iter.hasNext())
        {
            String item =  iter.next();
            System.out.println(item);
        }
        
        // : 后面的类型 一定要支持迭代器的类型才行 也就是实现Iterabale接口
        for(String data: mc){  //还是要干迭代器干的事
            System.out.println(data);
        }
        //如果使用反汇编工具 这两个循环生成的代码是一样的
    }

}


AbstractList内部实现 iterator()  返回一个真正的类型对象

AbstractList实现了List接口


找到了迭代器最原始的接口

  

 回到AbstractList类中查看iterator()  中的 return 语句

Itr类是封装在AbstractList类中的内部嵌套类,实现内部类原因是对外界是没必要知道的, 设计模式的原则内部实现尽量不要暴露给外界,除非有绝对的必要性。

 

 

在类图结构中 Iterator对应代码中的是  ,First() 在 Iterator 接口中被省略了。调用了一次hasNext(),然后再调用next(),直接就能得到First。Next() 对应的 是 。IsDone() 对应代码中的 hasNext()。CurrentItem() 已经被合并在 ,直接next()就返回对象。

Aggregate 是聚合对象 对应代码中的 。可迭代的对象就是聚合对象。CreateIterator() 对应代码中的 

Concretelterator 对应代码中的 

ConcreteAggregate 对应的是 的子类。在java库中几乎所有的集合类型,比如List,ArrayList,Set,都实现了 Iterable 接口。

Aggregate 和 Iterator 是稳定的。ConcreteAggregate 和 Concretelterator 是变化的。

 

要点总结

迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。
迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。(不要在迭代的过程中删除元素)
 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值