Android设计模式系列————开篇

【安卓架构师】【高焕堂】【android从程序员到架构师】从零开始进阶安卓架构师 从第一次写出Hello World,到成为一个优秀的工程师的距离有多远? android从程序员到架构师之路课程,遵循敏捷的迭代过程,从思想、方法、模式、范例和成功案例各种不同角度,带你学习从设计到代码的途径。让你在活泼的过程中,轻松地从原本的代码世界,迅速熟悉设计的新天地。 学习目录 1.复习基本OOP知识a 2.复习基本OOP知识b 3.复习基本OOP知识c 20:00 阅读详情

=======================2011-08-26==================================
有时候,最难的是坚持;有时候缺少的是信念。
=======================2011-08-07==================================
从接触设计模式到如今大概4年左右的时间,一直都想有朝一日定要精通,坐于床头,侧望左右,设计模式的书买了7,8本了,也看了很多参考和视频,也用到了一些。但是今天我终于停下来,停下来梳理,停下来欣赏,也停下来反省,总之,我今天停下来了,是为了走的更好,走的更远。
 

如果有幸我能够把这个系列写到23+N,我想至少我的技术上会为我增色不少,会为我带来更强烈的信心;
如果有幸我能够把这个系列写到23+N,我想至少我去买者方面书籍的时候,我不会那么动心了,我也许不深,你也未必;
如果有幸我能够把这个系列写到23+N,我想至少后面架构和Android的底层我会更加了解,我会看的更清楚,也看的更远。
我自己也是这么想得,所以我会坚持,我要把这个进行到底,写下去,写完23,我写+N,写完SDK,我写别人的开源项目,写完开源,我写我个人项目,写完个人项目,我写我自己的开源项目,至少我要写到我认为我应该继续写的时候,我如是想,也如是做!
我就是这么想的!
=======================2011-07-29==================================
看了很多年的设计模式,也看了很多种设计模式,也在工作中用了几个常见的设计模式。
Android中,包括源码和一些开源项目,用到了很多经典设计模式,而且也用的非常的精彩。
学习Android也有一些日子了,有空的时候看看源代码,看看开源项目的代码,自己也会再工作中写写代码。
今天,斗胆,基于Android(其实就是java),把自己对设计模式的一些粗浅认识,默默的分享出来,希望能得到各位同仁的指点,以期设计能力更进一步。
我将以《设计模式:可复用面向对象软件的基础》为准,发掘Android中各种设计模式的使用情况,提取核心部分,做为实例。
因为不需要写代码,应用场景又一般是Android中自带的,所以文中可能会注重意图介绍和UML结构图的绘制,然后具体设计模式的本身和扩展还需要各位参考其他资料。
下面我列举一些重要的认识点:

设计模式,提供了很多软件工程问题所需处理的解决方案。

根据模式的目的可分为3类:
1.创建型模式:与对象的创建有关。
2.结构性模式:处理类与对象的组合。
3.行为性模式:对类或对象怎样交互和怎样 分配职责进行描述。

面向对象设计的2个基本原则:
1.针对接口编程,而不是针对实现编程。
2.优先使用对象组合,而不是类继承。

面向对象设计的5个设计原则:
1.单一职责原则(SRP)
2.开放封闭原则(OCP)
3.Liskov替换原则(LSP)
4.依赖倒置原则(DIP)
5.接口隔离原则(ISP)

23中设计模式:
1.创建型模式:
(1).工厂方法模式
(2).抽象工厂模式
(3).创建者模式
(4).原型模式
(5).单例模式
2.结构型模式:
(6).适配器模式
(7).桥模式
(8).组合模式
(9).装饰模式
(10).外观模式
(11).享元模式
(12).代理模式
3.行为型模式
(13).解释器模式
(14).模板方法模式
(15).职责链模式
(16).命令模式
(17).迭代器模式
(18).中介者模式
(19).备忘录模式
(20).观察者模式
(21).状态模式
(22).策略模式
(23).访问者模式
除此之外,后来人发现很多新的模式,如空模式等。

下面列举几个常见的问题导致重新设计,可能需要设计模式来分析解决:
1.通过显示的指定一个类来创建对象
2.对特殊操作的依赖
3.对硬件和软件平台的依赖
4.对对象表示或实现的依赖
5.算法依赖
6.紧耦合
7.通过生产子类来扩展功能
8.不能方便的对类进行修改

软件的设计臭味:
1.僵化性
2.脆弱性
3.顽固性
4.粘滞性
5.不必要的复杂性
6.不必要的重复
7.晦涩性
... ...
总而言之,一句话,面向对象特性+原则+模式,折腾来折腾去就是这么个回事。


 

Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用。在android UI设计,几乎所有的widget和布局类都依靠这两个类。
组合模式,Composite Pattern,是一个非常巧妙的模式。几乎所有的面向对象系统都应用到了组合模式。

1.意图
将对象View和ViewGroup组合成树形结构以表示"部分-整体"的层次结构(View可以做为ViewGroup的一部分)。
 

组合模式使得用户对单个对象View和组合对象ViewGroup的使用具有一致性。
热点词汇: 部分-整体 容器-内容 树形结构 一致性 叶子 合成 安全性 透明性

2.结构

 

针对View和ViewGroup的实际情况,我们选择安全式的组合模式(在组合对象中添加add,remove,getChild方法),添加少许的注释,我们把上图修改为:

 

3.代码
View类的实现:

?
1
2
3
4 public class View{
        //... ...
        //省略了无关的方法
}

ViewGroup的实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 public abstract class ViewGroup extends View{
    /**
     * Adds a child view. 
     */
    public void addView(View child) {
        //...
    }
 
    public void removeView(View view) {
        //...
    }
 
    /**
     * Returns the view at the specified position in the group.
     */
    public View getChildAt(int index) {
        try {
            return mChildren[index];
        } catch (IndexOutOfBoundsException ex) {
            return null;
        }
    }
 
    //other methods
}

4.效果
(1).结构型模式
(2).定义了包含基本对象和组合对象的类层次结构。这种结构能够灵活控制基本对象与组合对象的使用。
(3).简化客户代码。基本对象和组合对象有一致性,用户不用区分它们。
(4).使得更容易添加新类型的组件。
(5).使你的设计变得更加一般化。

观察者模式,是一种非常常见的设计模式,在很多系统中随处可见,尤其是涉及到数据状态发生变化需要通知的情况下。
本文以AbstractCursor为例子,展开分析。
观察者模式,Observer Pattern,是一个很实用的模式,本人曾经接触到的各种平台以及曾经参与项目中打印模板解释器中都用到了此模式。

1.意图


定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
热门词汇: 依赖 发布-订阅 事件 通知 更新 监听 

2.结构


这是一个最简单的观察者模式,目标对象能够添加和删除观察者,当自己某种状态或者行为发生改变时,可通过notify通知注册的观察者进行更新操作。
分析AbstractCursor的具体情况,我们发现实际工作有时需要对观察者进行统一管理,甚至观察者类型有很多种而又可以分成几个系列,这个时候是要复杂的多,通过合理的分层这个问题很好解决。下面根据具体情况,我们画出Android中abstractCurosr中用到的观察者模式结构图:


观察者分成了两个系列。

3.代码
列举其中相关核心代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public abstract class AbstractCursor {
     //定义管理器
     DataSetObservable mDataSetObservable = new DataSetObservable();
     ContentObservable mContentObservable = new ContentObservable();
      
     //注册和卸载两类观察者
     public void registerContentObserver(ContentObserver observer) {
         mContentObservable.registerObserver(observer);
     }
  
     public void unregisterContentObserver(ContentObserver observer) {
         // cursor will unregister all observers when it close
         if (!mClosed) {
             mContentObservable.unregisterObserver(observer);
         }
     }
  
     public void registerDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.registerObserver(observer);
          
     }
  
     public void unregisterDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.unregisterObserver(observer);
     }
  
     //2类通知方法
     protected void onChange( boolean selfChange) {
         synchronized (mSelfObserverLock) {
             mContentObservable.dispatchChange(selfChange);
             if (mNotifyUri != null && selfChange) {
                 mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
             }
         }
     }
  
     protected void notifyDataSetChange() {
         mDataSetObservable.notifyChanged();
     }
}

  再看看Observable<T>类和DataSetObservable类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public abstract class Observable<T> {
     /**
      * 观察者列表
      */
     protected final ArrayList<T> mObservers = new ArrayList<T>();
  
     public void registerObserver(T observer) {
         if (observer == null ) {
             throw new IllegalArgumentException( "The observer is null." );
         }
         synchronized (mObservers) {
             if (mObservers.contains(observer)) {
                 throw new IllegalStateException( "Observer " + observer + " is already registered." );
             }
             mObservers.add(observer);
         }
     }
  
  
     public void unregisterObserver(T observer) {
         if (observer == null ) {
             throw new IllegalArgumentException( "The observer is null." );
         }
         synchronized (mObservers) {
             int index = mObservers.indexOf(observer);
             if (index == - 1 ) {
                 throw new IllegalStateException( "Observer " + observer + " was not registered." );
             }
             mObservers.remove(index);
         }
     }
      
     public void unregisterAll() {
         synchronized (mObservers) {
             mObservers.clear();
         }        
     }
}

  和

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class DataSetObservable extends Observable<DataSetObserver> {
     /**
      * 数据发生变化时,通知所有的观察者
      */
     public void notifyChanged() {
         synchronized (mObservers) {
             for (DataSetObserver observer : mObservers) {
                 observer.onChanged();
             }
         }
     }
     //... ... (其他方法)
}

  观察者DataSetObserver类是一个抽象类:

?
1
2
3
4
5
public abstract class DataSetObserver {
     public void onChanged() {
         // Do nothing
     }
}

  所以我们具体看它的子类:

?
1
2
3
4
5
6
7
8
9
10
11
public class AlphabetIndexer extends DataSetObserver{
     /*
      * @hide 被Android系统隐藏起来了
      */
     @Override
     public void onChanged() {
         //观察到数据变化,观察者做自己该做的事情
         super .onChanged();
         mAlphaMap.clear();
     }
}

  ContentObserver也是类似。

4.效果
(1).行为型模式
(2).目标和观察者间的抽象耦合(经典实现)。
(3).支持广播通信(相信这点Android开发者看到后应该有启发吧)。
(4).注意意外的更新,这也是观察者更新进行管理的原因之一


 

单例模式,可以说是GOF的23种设计模式中最简单的一个。
这个模式相对于其他几个模式比较独立,它只负责控制自己的实例化数量单一(而不是考虑为用户产生什么样的实例),很有意思,是一个感觉上很干净的模式,本人很喜欢这个模式。
Android中很多地方都用到了单例模式,本文以输入法管理者InputMethodManager为例,展开分析。


单例模式,Singleton Pattern,能够以其特有的优势,替代系统中全局变量,应用非常广泛。

1.意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
热门词汇:单例 唯一 私有构造

2.结构

Android中有很多系统级别的全局变量,如时间,输入法,账户,状态栏等等,android中对这些都直接或者有些间接用到了单例模式。
以输入法为例,把上图修改为实际情况:


非常的简单,但是有一点,从上面我们也看到了synchronized关键字,在多线程的环境下,单例模式为了保证自己实例数量的唯一,必然会做并发控制。
类似这种线程安全的单例,跨进程的单例,参数化的单例等等的情况,确实超出本文的范围,而且都涉及到很多东西,是一个很大的话题,不好展开。

3. 代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public final class InputMethodManager {
     static final Object mInstanceSync = new Object(); //同步
     //内部全局唯一实例
     static InputMethodManager mInstance;
  
     //对外api
     static public InputMethodManager getInstance(Context context) {
         return getInstance(context.getMainLooper());
     }
      
     /**
      * 内部api,供上面的外部api调用
      * @hide 系统隐藏的api
      */
     static public InputMethodManager getInstance(Looper mainLooper) {
         synchronized (mInstanceSync) {
             if (mInstance != null ) {
                 return mInstance;
             }
             IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
             IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
             mInstance = new InputMethodManager(service, mainLooper);
         }
         return mInstance;
     }
}

  客户端调用,比如contextimpl中的getSystemService()方法中如下调用:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ContextImpl extends Context{
     @Override 
     public Object getSystemService(String name) {
         if (WINDOW_SERVICE.equals(name)) {
             //... ... 省略下面n个if,else if
         } else if (INPUT_METHOD_SERVICE.equals(name)) {
             //获取输入法管理者唯一实例
             return InputMethodManager.getInstance( this );
         }  else if (KEYGUARD_SERVICE.equals(name)) {
              //... ... 省略下面n个if,else if
         } else if (ACCESSIBILITY_SERVICE.equals(name)) {
             //又见单例,无处不在
             return AccessibilityManager.getInstance( this );
         } else if (LOCATION_SERVICE.equals(name)) {
             //... ... 省略下面n个if,else if
         }  else if (NFC_SERVICE.equals(name)) {
             return getNfcManager();
         }
         return null ;
     }
}

  非常简单,干净的一个模式。

4.效果
(1).创建型模式。
(2).对唯一实例的受控访问。
(3).避免全局变量污染命名空间。
(4).允许对操作和表示的精化。
(5).比类操作更灵活。 

模板方法,和单例模式是我认为GOF的23中最简单的两种模式。
但是我个人对模板方法的经典思想特别推崇,虽然模板方法在大对数情况下并不被推荐使用,但是这种通过父类调用子类的方法,使用继承来改变算法的一部分,是面向对象的一种基本认识。
打比方说父亲有很多理想,就行医救人吧,但是父亲医术不行,只能靠儿子,儿子长大后遵从父亲大志,春风拂面,妙手回春,实现了父亲的理想,儿子做的事情早在出生前就定下来了,是父亲之前久定好的模板。


认识到模板方法的这种思想,父类可以让未知的子类去做它本身可能完成的不好或者根本完成不了的事情,对框架学习大有帮助。
本文以View中的draw方法为例,展开分析。
模板方法,TemplateMethod,光是学习这个模式,就会对你产生长远影响的一个模式。

1.意图
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 
热门词汇:骨架 步骤 结构 延迟到子类 

2.结构 

定义了几个步骤1,2,3等,在模板方法中按照一定的结构顺序执行这些步骤。父类的方法可以有缺省实现,也可以是一个空实现,即所谓的钩子操作。
结合实际情况,我们画出View中draw方法涉及到的几个步骤方法如下:


学习模板方法对于我们了解框架的基类实现,生命周期和流程控制非常有帮助,我觉得是务必要掌握的一个模式。

3.代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class View{
     /**
      * 钩子操作,空实现
      */
     protected void onDraw(Canvas canvas) {
     }
  
     /**
      *钩子操作,空实现
      */
     protected void dispatchDraw(Canvas canvas) {
     }
  
     //算法骨架
     public void draw(Canvas canvas) {
        if (!verticalEdges && !horizontalEdges) {
             // 步骤1
             if (!dirtyOpaque) onDraw(canvas);
  
             // 步骤2
             dispatchDraw(canvas);
  
             // 步骤3
             onDrawScrollBars(canvas);
  
             return ;
         }
     }
     //... ...
}

  我们看看系统组件TextView的实现:

?
1
2
3
4
5
6
public class TextView{
     @Override
     protected void onDraw(Canvas canvas) {
         //大量自定义实现代码
     }
}

  如果我们自定义View的话,我们一般也是重写onDraw方法即可:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyView extends View {
  
     public MyView(Context context) {
         super (context);
     }
  
     @Override
     protected void onDraw(Canvas canvas) {
         super .onDraw(canvas);
     }
  
     @Override
     protected void dispatchDraw(Canvas canvas) {
         super .dispatchDraw(canvas);
     }
      
}

4.效果
(1).模板方法是一种代码复用的基本技术。它们在类库中尤为重要,它们提取了类库中的公共行为。
(2).模板方法导致一种方向控制结构,"好莱坞法则":"Don't call me,i will call you.",即一个父类调用子类的操作,而不是相反。
(3).模板调用操作的类型有具体的操作,具体的AbstracClass操作,原语操作,工厂方法,钩子操作。少定义原语操作。
(4).Android中对这些重定义操作的命名喜欢在方法前加一个前缀on。
(5).模板方法使用继承来改变算法的一部分。策略模式使用委托来改变整个算法。

 

备忘录模式,在工作代码中,要么不用,要么经常用到。
举个例子,程序员喜欢写代码,coding,coding,这个时候它的状态是很high,但是每隔一段时间总要去上一下厕所,状态是放松relax,上完测试归来后又恢复到high的状态,继续coding。这个过程对于身后的老板来说,它默认同意你离开去上厕所,他也希望你回来后恢复high的状态继续工作,但是你在这个过程中上厕所的这件事,他是不需要了解细节的,而且做为当事人你也不希望他了解你上厕所的细节吧,你只要回来后恢复激情high着继续工作,老板应该就不会挑你的刺。


这就是备忘录模式。
本文今天就Canvas的一个save(),restore()操作分析一下,但是有一点,看完本文,如果不懂备忘录模式的,应该还是不懂,但是canvas是 Android的一场大戏,说一说它的特色,对深入学习android绝对有帮助。
学习备忘录模式,通过保存状态,恢复状态的内部实现,对了解一些莫名其妙的看上去无用其实很重要的操作有拨开云雾见青天的作用。

1.意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到先前保存的状态。
热门词汇:标记 状态 备忘录 原发器

2.结构和代码

组织者,把原发器的状态State(全部或者部分状态,一般是变量的值),通过CreateMemento()方法保存起来,继续运行后,等待合适的时机,在通过SetMemento()方法可以再次恢复到之前的状态。在这个过程中,我们并没有对这些状态做任何的访问和设置,实际上这些状态都是私有的,对外是禁止访问的,我们只是通过Memento对象的两个最简单的方法就达到了这个效果。Memento经常写成Originator的内部类。
在Android中,Canvas有两个方法 save()和restore()方法再做图形变换的时候使用的非常多,因为涉及到跨语言的问题,我不好就认定这个用的是备忘录模式,但是它的这种思想绝对是备忘录的思想。


我们来读一读它源代码的注释吧,首先看save()保存状态:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Canvas {
     /**
      * Saves the current matrix and clip onto a private stack. Subsequent
      * calls to translate,scale,rotate,skew,concat or clip Rect,clipPath
      * will all operate as usual, but when the balancing call to restore()
      * is made, those calls will be forgotten, and the settings that existed
      * before the save() will be reinstated.
      */
     /**
      *保存当前的矩阵和剪裁到一个私有的堆栈,其实矩阵和剪裁就是当前Canvas的状态State
      */
     public native int save();
}

  再看恢复状态restore():

?
1
2
3
4
5
6
7
8
9
10
11
public class Canvas {
     /**
      * This call balances a previous call to save(), and is used to remove all
      * modifications to the matrix/clip state since the last save call. It is
      * an error to call restore() more times than save() was called.
      */
     /**
      * 移除自上次保存操作后所做的修改,恢复到之前的状态,因为是堆栈实现,所以pull操作不能不等于push操作,save()和restore()应该成对使用,否则恢复的状态就很有可能是错误的
      */
     public native void restore();
}

  从上面的两个方法中,它们实现了自我状态的恢复,实际上我们只是执行了两个没有接触任何内部信息的方法,实际上这两个方法就是在操作我们看不到的这些内部状态信息。

3.效果
(1).保持封装边界,把很复杂的原发器的内部信息对外部其他对象隐藏起来。
(2).简化的原发器,把状态操作无形中转化到客户手里,简化了原发器的某些实现。
(3).也要注意注意备忘录的管理代价。

 

享元模式,给我的感觉就是对象池,缓存单例对象。
java中的享元模式最经典的例子就是String类了,还有一个最容易理解的就是word文档字符共享的例子,也是享元模式的经典应用。
本文对Android中的sql编译类SQLiteCompiledSql说明,展开分析,也是很容易理解的一个例子,其实,android SDK中必然有很多地方需要用到享元模式。


享元模式,Flyweight  Pattern,说的严重点,一些程序如果不使用享元模式的话,根本不能使用面向对象的方法实现,对象会多的撑爆你的内存:"用面向对象思想设计的应用常常会面临对象实例过多的问题"。 

1.意图
运用共享技术有效地支持大量细粒度的对象。
热门词汇:共享 池 缓存 内部状态 外部状态 对象 单例 

2.结构 


这是一个完整的享元模式结构图。
客户端通过享元工厂获取享元对象,享元对象的创建则根据工厂的享元池来控制,如果有享元池中没有这个对象,则创建这个对象并保存到享元池中,如果享元池中有这个对象,则直接使用这个对象。因为享元对象在共享的同时,说明它重用属性的不变性,不然都是变化的东西,不存在共享,这些不变得属性我们称之为内部状态,独立与外部场景。而另外一些属性,可以根据外部场景变化的,我们称之为外部状态,在上图中我们也看到,我们可以通过Operation改变外部状态。
Android中SQLiteCompiledSql的使用,其实是很多数据库系统典型的实现。从应用启动,通过各种数据库操作,我们不知道进行了多少次的查询操作,而这些操作中又有相当一部分sql语句是相同的,这些编译后的sql编译对象其实是一样的,是可以共用共享的,其实就是缓存。SQLiteCompiledSql就是这样的一个需要共享的享元对象,画出相关的UML图如下:


其中SqliteDatabase中的mCompiledQuerie就是存放享元对象的容器。
通过这种方式大大减少了sql编译对象的创建,提高了数据库操作的性能。

3.代码
享元对象类SQLiteCompiledSql,主要是内部状态sql语句:

?
1
2
3
4
5
class SQLiteCompiledSql {
     private String mSqlStmt = null ;
     native_compile(sql); 
     native_finalize();
}

享元工厂类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class SQLiteDatabase{
      Map<String, SQLiteCompiledSql> mCompiledQueries = Maps.newHashMap();
      SQLiteCompiledSql getCompiledStatementForSql(String sql) {
         SQLiteCompiledSql compiledStatement = null ;
         boolean cacheHit;
         synchronized (mCompiledQueries) {
             if (mMaxSqlCacheSize == 0 ) {
                 return null ;
             }
             cacheHit = (compiledStatement = mCompiledQueries.get(sql)) != null ;
         }
         if (cacheHit) {
             mNumCacheHits++;
         } else {
             mNumCacheMisses++;
         }
         return compiledStatement;
     }
  
     private void deallocCachedSqlStatements() {
         synchronized (mCompiledQueries) {
             for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) {
                 compiledSql.releaseSqlStatement();
             }
             mCompiledQueries.clear();
         }
     }
  
     void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) {
          //省略具体代码
     }
}

  其他类几个相关类是对这个集合的操作相关,和享元模式没有什么实质性的关系,代码省略。

4.效果
(1).结构型模式;
(2).节约存储的方法:用共享减少内部状态的消耗,用计算时间换取对外部状态的存储;
(3).缓冲。

命令模式,在.net,java平台的事件机制用的非常多,几乎每天都与之打交道。
Android中对我印象最深的就是多线程多进程的环境,所以必然大量使用到Runbable,Thread,其实用的就是最简单的命令模式。
命令模式,Command Pattern,把请求封装为一个对象,多么巧妙的一个说法啊。

1.意图


将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
热门词汇: 动作 事物 请求封装 排队 打包 异步 

2.结构


Command接口提供了Execute方法,客户端通过Invoker调用命令操作来调用Recriver,绕了一大圈,但是却把具体对Receiver的操作请求封装在具体的命令中,是客户端对recriver的操作清晰简明。
但是在实际项目中,我们常常忽略Receiver,而把命令对象的目标对象直接设置为子类自己的成员变量或者作为execute()方法的临时变量。
以Android中的Runnable(在java.lang包下)为例,我们画出UML结构图如下:


想不到我们天天写的代码无意识中就是用到了命令模式,所谓模式,就是无所不在。

3.代码
命令接口Runnable定义如下:

?
1
2
3
public interface Runnable {
     public abstract void run();
}

调用者Thread简化版代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//命令模式这里不需要继承Runnable接口,但是这里考虑到实际情况,比如方便性等,继承了Runnable接口,实现了run方法,这个是Thread自身的运行run的方法
class Thread implements Runnable {
     private Runnable target;
      
     public Thread(Runnable target) {
         this .target = target;
     }
  
      public synchronized void start() {
  
         if (threadStatus != 0 || this != me)
             throw new IllegalThreadStateException();
         group.add( this );
         start0(); //这个是本地方法,调用run方法
         if (stopBeforeStart) {
         stop0(throwableFromStop);
     }
     }
  
     //可选
     public void run() {
     if (target != null ) {
         target.run();
     }
     }
}

  客户端只需要new Thread(new Runnable(){}).start()就开始执行相关的一系列的请求,这些请求大部分都是实现Runnable接口的匿名类。

4.效果
(1).行为型模式;
(2).将调用对象的操作和知道如何实现该操作的对象解耦;
(3).多个命令可以装配成一个复合命令;
(4).增加新的命令很容易。

 

工厂方法模式,往往是设计模式初学者入门的模式,的确,有人称之为最为典型最具启发效果的模式。
Android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具管理类。
今天以ThreadFactory举例说明一下简单工厂模式和工厂方法模式。 
工厂方法模式,Factory Method,简单的方式,不简单的应用。

1.意图
定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方式模式使一个类的实例化延迟到其子类。
热门词汇:虚构造器 延迟 创建对象 子类 

2.结构图和代码
我们先看看标准的工厂方法结构图:


先抽象的产品类,抽象的工厂类,然后用客户端具体的工厂生产相应的具体的产品,但是客户端并不知道具体的产品是怎么生产的,生产的过程封装在工厂里。所以说,某种程度上,工厂方法模式改变了我们直接用new创建对象的方式,一个很好的开始,意义重大。
以ThreadFactory为例:

这张图其实和原本的结构图有细微的区别,那就是参数化得工厂,而且从业务意义上也有些不同,但是思想是一样的。
我们来看下具体的代码:

?
1
2
3
4
5
6
7
8
9
//抽象产品
public interface Runnable {
     public abstract void run();
}
  
//抽象工厂
public interface ThreadFactory {
     Thread newThread(Runnable r);
}

下面是具体的实现:
比如AsyncTask类中工厂的具体实现如下:

?
1
2
3
4
5
6
7
8
9
10
11
//工厂实现类
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
     private final AtomicInteger mCount = new AtomicInteger( 1 );
 
     public Thread newThread(Runnable r) {
         return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
     }
};
//那么产品类在哪里呢?
//做为参数Runnable r,我们可以创建千千万万个此系列的产品类
//同理,我们可以创建另外类似的工厂,生产某种专门的线程,非常容易扩展

看到这里,我们一方面为它的生产便利性感叹,一方面又为没创建某类产品都要创建一个工厂而感到繁琐,所以我们下面介绍简单工厂,它的结构图如下:


简单工厂把抽象工厂去掉了,你就创建一个专门生产某类产品就好。在一些特定而又不负责的领域非常实用方便套用这个模式。
在Android中的Connection类中使用到了这个类:


其中Connection这个抽象类,既充当抽象产品类,也充当具体工厂类。
因为这种情况下,我们往往需要的是马上生产子类,getConnection方法往往是静态的,所以简单工厂,也叫静态工厂方法。
我们看看代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
abstract class Connection{    
     static Connection getConnection(
             Context context, HttpHost host, HttpHost proxy,
             RequestFeeder requestFeeder) {
  
         if (host.getSchemeName().equals( "http" )) {
             return new HttpConnection(context, host, requestFeeder);
         }
  
         // Otherwise, default to https
         return new HttpsConnection(context, host, proxy, requestFeeder);
     }
}

这就是简单工厂,一个很简单的参数化工厂,真的很简单。

3.效果
1. 创建型模式;
2.参数化工厂方法模式得到相应的对象;
3.为子类提供挂钩;
4.连接平行的类层次。

 

 

 

本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2012-01/52269.htm

设计模式基于Android(一) 经典的23种设计模式是由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides(合称“Gang of Four”)在他们的书《设计模式:可复用面向对象软件的基础》中定义的。在 Android 开发中,虽然23种经典设计模式都有可能用到,但一些模式在实际开发中更为常见和实用。尽管有些模式在不同环境中有特定的实现方式,但核心思想依然适用。这些设计模式在Android开发中常见且实用,它们可以帮助我们开发者创建更结构化、可维护和扩展性强的应用程序。 阅读详情

相关推荐

无需UMAT:基于Abaqus内置模型实现形状记忆聚合物结构的热-力耦合仿真

本文详细介绍了如何利用Abaqus内置模型实现形状记忆聚合物(SMP)的热-力耦合仿真,无需编写复杂的UMAT子程序。通过广义Maxwell模型和Neo-Hookean模型的组合应用,结合完整的热-力耦合分析流程,帮助工程师高效模拟SMP的形状记忆行为。文章还提供了工程应用案例和常见问题解决方案,为相关领域的研究和设计提供实用指导。

weixin_34005090的博客 116

Android设计模式系列(0)--开篇

=======================2011-08-26==================================有时候,最难的是坚持;有时候缺少的是信念。=======================2011-08-07==================================从接触设计模式到如今大概4年左右的时间,一直都想有朝一日定要精通,坐于床头,侧望...

dianan1505的博客 151

SAP-PP 返工订单成本归集优化:从物料结算到成本中心的配置与增强实践

本文深入探讨SAP-PP模块中返工订单成本归集的优化方案,重点解析从物料结算到成本中心的配置与增强实践。通过结算参数文件配置、分配结构调整及增强开发实战,解决返工费用误计入物料成本的问题,确保财务核算精准性。文章还提供测试验证方案与常见报错处理技巧,助力企业实现成本数据清晰流向分析。

weixin_29260291的博客 363

安卓设计模式应用总结

####1.建造者模式建造者模式顾名思义,类似一个大楼都是按照一砖一瓦建造完成, 他通常结合链式调用一起使用该模式Android 比较热门的第三方框架均有使用举例:Rxjava, Retrofit, Okhttp, Geendao, 等等#####2.观察者模式观察者模式是一种行为模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

weixin_38504171的博客 1556

JS逆向-快手__NS_hxfalcon参数分析

现在快手H5接口都需要__NS_hxfalcon这个参数,这篇文章就是逆向这个参数

ckcookies的博客 4073

电源完整性之Cadence Sigrity Power DC_IR_Drop仿真

之前和大家分享过电源完整性之仿真设计原理链接: link.今天接着上一篇文章总结一下电源直流压降的的仿真操作流程及一些simulation中的设置参数,用到的时候Cadence Sigrity 中的Power DC组件,下面开始享受仿真的快乐吧: 1.仿真模式选择与文件导入 选择Cadence Sigrity下的Power DC组件,然后先择licence,最后就可以打开我们之前转化好的.SPD文件。操作如下图: 2.设置层叠信息和过孔焊盘参数 层叠信息:每层的介质厚度、材料、介电常数、介质损耗角等,如

刘小同学的博客 1万+

Android中常用的设计模式

一:参考文档先介绍参考文档(或许我们更容易明白):另记录本人可参考 QQ15 MobileSafe 两个Demo有哪些在实际 Android 项目中用到的设计模式?Android开发中常见的设计模式Android中常见的设计模式Android设计模式之23种设计模式一览Android中常用设计模式二:然后总结一下其总结内容多根据参考文献文档而来,还请了解文档内容(一)什么是设计模式1. 基本定义:...

豆子的博客 1万+

WorkBuddy任务对话上下文管理:Token、compact与上下文窗口实战指南

在大语言模型应用中,Token作为文本处理的最小单位,直接决定上下文窗口的消耗速度,而上下文窗口则限定了单次对话可承载的信息总量。当对话超出窗口限制时,compact压缩机制会触发有损摘要,导致关键约束丢失或工具调用结果被稀释。合理管理上下文不仅能提升多步骤任务的稳定性,还能显著降低Token成本与响应延迟。在文档处理、代码开发、多步自动化等场景中,通过主动压缩、状态外置、分段喂入等策略,可有效避免任务后期遗忘、版本混乱等问题。本文围绕WorkBuddy的上下文管理机制,从Token与compact的底层原

weixin_29055699的博客 389

安卓开发之设计模式

这次来学习一下安卓开发中几种常见的设计模式,主要参考AndroidCot。 安卓开发中的设计模式大致上可分为如下几类: 所谓设计模式其实更像是在编写代码时的经验总结,使用这些模式规范能让我们的程序更健壮稳定、容易扩展。此外在编写面向对象程序时,我们也需要遵循以下6个原则: 原则 描述 单一职责原则 一个类只负责一个功能领域中的相应职责 开闭原则 对象应该对于扩展是开放的,但是对于修改是封闭的 里氏替换原则 所有引用基类的地方必须能透明地使用其子类的对象 依赖倒置原则 主要是实现

iris的博客 1229

感应电机无速度传感器FOC控制原理与Simulink仿真实践

无速度传感器FOC控制是电机驱动领域的重要技术,通过算法重构实现仅依赖电气参数的闭环控制。其核心原理基于电机数学模型,利用Clark/Park变换和滑模观测器估算转子位置和转速。这种技术在工业伺服系统中具有显著价值,能有效降低系统成本并提高可靠性。典型应用场景包括纺织机械、风机驱动等需要精确转速控制的设备。本文以感应电机为例,详细解析了无感FOC的Simulink实现方法,特别关注滑模观测器设计和双闭环控制策略,为工程师提供可直接复用的参数调优经验。

weixin_29189987的博客 259

具身智能数据采集的工程化指南:从时间同步到质量校验

具身智能的模型训练离不开高质量的多模态轨迹数据,而数据采集并非简单的传感器记录。真实场景中,相机图像、机械臂关节状态与力觉信息必须在时间轴上精确对齐,标定的漂移和格式混乱会让看似正常的数据无法用于训练。时间同步与标定一致性,是决定数据质量的核心技术环节。在机器人抓取、操作等工程应用中,一套包含多传感器同步、轻量记录脚本、自动化质量校验与版本管理的数据采集流程,能大幅降低数据生产的失败率。本文从工程视角拆解具身数据采集中的典型问题,并给出可落地的流程设计与校验方法,帮助团队构建可持续迭代的高质量数据集。

weixin_30603633的博客 510

安卓设计模式理解

前言 关于安卓的设计模式这个老生常谈的话题,多余的话就不多赘述了。文章内容仅限于我个人对设计模式的理解,便于记录和复盘。 说明 主流的3中设计模式已在下文中列出,现针对设计模式的 MV 先做说明,再对各个设计模式的层级叙述。 M–>Model(模型层,以下简称M层) 即代码中各个bean或者model这种对象类。通常我们在和后台接口数据交互的时候都要书写一个对应的数据模型,通过json解析后用于装填数据方便我们存取做数据的操作。 V–>View(视图层,以下简称V层) 即我们绘制的xml布局

heromrwang的博客 375

如何通过 Python 爬虫抓取并分析政府开放数据

通过本文的介绍,我们展示了如何使用Python 爬虫抓取并分析政府开放数据。通过requests获取政府开放数据的 API 接口数据。使用和pandas进行数据清洗与存储。使用matplotlib对数据进行可视化。你可以根据不同的政府开放平台和数据集进行调整,应用于不同领域的数据分析,如公共健康、交通、环保等。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1077

Android复习系列⑦之《设计模式》

1mvc/mvp/mvvm MVC:Model-View-Controller,是一种分层解偶的框架,Model层提供本地数据和网络请求,View层处理视图,Controller处理逻辑,存在问题是Controller层和View层的划分不明显,Model层和View层的存在耦合。 MVP:Model-View-Presenter,是对MVC的升级,Model层和View层与MVC的意思一致,但Model层和View层不再存在耦合,而是通过Presenter层这个桥梁进行交流。 MVVM:Model-Vie

路漫漫其修远兮,吾将上下而求索 927

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

安卓开发用到的设计模式(1)创建型模式

本文介绍了在Android开发中常用的创建型设计模式及其应用场景。单例模式用于确保类只有一个实例,如系统服务和数据管理器;工厂模式通过隐藏创建逻辑来简化对象创建,如Fragment和IntentService的实例化;抽象工厂模式用于创建一系列相关对象,如主题系统和数据访问层;建造者模式通过分离构建过程与表示来创建复杂对象,如Dialog和Retrofit的配置;原型模式通过复制原型实例来创建新对象,如Intent的克隆和配置对象的复制。

分享Android应用和系统开发、音视频编码、性能优化相关知识 1404

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

安卓开发用到的设计模式(3)行为型模式

1. 命令模式(Command Pattern) 2. 策略模式(Strategy Pattern) 3. 观察者模式(Observer Pattern) 4. 模板方法模式(Template Method Pattern) 5. 责任链模式(Chain of Responsibility Pattern) 6. 状态模式(State Pattern) 7. 访问者模式(Visitor Pattern) 8. 中介者模式(Mediator Pattern) 9. 迭代器模式(Iterator Pattern

分享Android应用和系统开发、音视频编码、性能优化相关知识 1316

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

上一篇: Android colors.xml (颜色大全)
下一篇: android——HorizontalScrollView
代号码农
博客等级 码龄16年 5粉丝 8原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值