Android 源码中的设计模式

DRV8818+STM32F042双极步进电机工业驱动实战指南 双极步进电机驱动是工业嵌入式运动控制的基础技术,其核心在于电流精确调控、微步细分实现与抗扰可靠运行。DRV8818PWPR作为高集成度驱动芯片,配合STM32F042K6等Cortex-M0 MCU,可在低成本、小体积约束下实现1/32微步、2.5A RMS输出及硬件级保护响应。该组合的技术价值体现在工业级温度适应性(-10℃~65℃)、电磁兼容鲁棒性(IEC 61000-4-2 ±8kV)与产线可维护性(拨码切换细分、LED分级故障指示)。典型应用场景涵盖轻型机器人关节、精密送料平台与视觉伺服定位系统。本 阅读详情

面向对象的六大原则

  • 单一职责原则所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。通俗的说,即一个类只负责一项职责,将一组相关性很高的函数、数据封装到一个类中。
  • 开闭原则对于扩展是开放的,这意味着模块的行为是可以扩展的。当应用的需求改变时,我们可以对模块进行扩展,使其具有满足那些改变的新行为。
    对于修改是关闭的,对模块行为进行扩展时,不必改动模块的源代码。通俗的说,尽量通过扩展的方式实现系统的升级维护和新功能添加,而不是通过修改已有的源代码。
  • 里氏替换原则使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。任何基类可以出现的地方,子类一定可以出现。在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立。在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
  • 依赖倒置原则高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合(各个模块之间相互传递的参数声明为抽象类型,而不是声明为具体的实现类)。
  • 接口隔离原则一个类对另一个类的依赖应该建立在最小的接口上。其原则是将非常庞大的、臃肿的接口拆分成更小的更具体的接口。
  • 迪米特原则又叫作最少知识原则,就是说一个对象应当对其他对象有尽可能少的了解。
    通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少,不关心被耦合或调用的类的内部实现,只负责调用你提供的方法。下面开始设计模式学习...

1. Singleton(单例模式)

作用:

保证在Java应用程序中,一个类Class只有一个实例存在。

好处:

由于单例模式在内存中只有一个实例,减少了内存开销。

单例模式可以避免对资源的多重占用,例如一个写文件时,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。

单例模式可以再系统设置全局的访问点,优化和共享资源访问。

使用情况:

建立目录 数据库连接的单线程操作

某个需要被频繁访问的实例对象

1.1 使用方法

第一种形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public  class  Singleton {
 
     /* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
     private  static  Singleton instance =  null ;
 
     /* 私有构造方法,防止被实例化 */
     private  Singleton() {
     }
 
     /* 懒汉式:第一次调用时初始Singleton,以后就不用再生成了
     静态方法,创建实例 */
     public  static  Singleton getInstance() {
         if (instance ==  null ) {
             instance =  new  Singleton();
         }
         return  instance;
     }
}

但是这有一个问题,不同步啊!在对据库对象进行的频繁读写操作时,不同步问题就大了。

第二种形式:

既然不同步那就给getInstance方法加个锁呗!我们知道使用synchronized关键字可以同步方法和同步代码块,所以:

1
2
3
4
5
6
public  static  synchronized  Singleton getInstance() {
     if (instance ==  null ) {
         instance =  new  Singleton();
     }
     return  instance;
}

或是

1
2
3
4
5
6
7
8
public  static  Singleton getInstance() {
      synchronized (Singleton. class ) {
          if (instance ==  null ) {
              instance =  new  Singleton();
          }
      }
      return  instance;
  }

获取Singleton实例:

1
Singleton.getInstance().方法()

1.2android中的Singleton

软键盘管理的 InputMethodManager

源码(以下的源码都是5.1的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  final  class  InputMethodManager {
//.........
      static  InputMethodManager sInstance;
//.........
      public  static  InputMethodManager getInstance() {
          synchronized (InputMethodManager. class ) {
              if (sInstance ==  null ) {
                  IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
                  IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
                  sInstance =  new  InputMethodManager(service, Looper.getMainLooper());
              }
              return  sInstance;
          }
      }

使用的是第二种同步代码块的单例模式(可能涉及到多线程),类似的还有
AccessibilityManager(View获得点击、焦点、文字改变等事件的分发管理,对整个系统的调试、问题定位等)
BluetoothOppManager等。

当然也有同步方法的单例实现,比如:CalendarDatabaseHelper

1
2
3
4
5
6
public  static  synchronized  CalendarDatabaseHelper getInstance(Context context) {
     if (sSingleton ==  null ) {
         sSingleton =  new  CalendarDatabaseHelper(context);
     }
     return  sSingleton;
}

注意Application并不算是单例模式

1
2
3
4
5
6
public  class  Application  extends  ContextWrapper  implements  ComponentCallbacks2 {
 
      public  Application() {
          super ( null );
      }
}

在Application源码中,其构造方法是公有的,意味着可以生出多个Application实例,但为什么Application能实现一个app只存在一个实例呢?请看下面:

在ContextWrapper源码中:

1
2
3
4
5
6
7
8
9
10
11
12
13
public  class  ContextWrapper  extends  Context {
     Context mBase;
 
     public  ContextWrapper(Context base) {
         mBase = base;
     }
 
     protected  void  attachBaseContext(Context base) {
         if (mBase !=  null ) {
             throw  new  IllegalStateException( "Base context already set" );
         }
         mBase = base;
     }

ContextWrapper构造函数传入的base为null, 就算有多个Application实例,但是没有通过attach()绑定相关信息,没有上下文环境,三个字。

然并卵

2. Factory(工厂模式)

 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
对同一个接口的实现类进行管理和实例化创建

这里写图片描述

假设我们有这样一个需求:

动物Animal,它有行为move()。有两个实现类cat和dog。为了统一管理和创建我们设计一个工厂模式。
同时两个子类有各自的行为,Cat有eatFish(),Dog有eatBone().

结构图:
这里写图片描述

Animal接口:

1
2
3
interface  animal {
     void  move();
}

Cat类:

1
2
3
4
5
6
7
8
9
10
11
public  class  Cat  implement s Animal{
 
     @Override
     public  void  move() {
         // TODO Auto-generated method stub
         System.out.println( "我是只肥猫,不爱动" );
     }
     public  void  eatFish() {
         System.out.println( "爱吃鱼" );
     }
}

Dog类:

1
2
3
4
5
6
7
8
9
10
11
public  class  Dog  implements  Animal{
 
     @Override
     public  void  move() {
         // TODO Auto-generated method stub
         System.out.println( "我是狗,跑的快" );
     }
     public  void  eatBone() {
         System.out.println( "爱吃骨头" );
     }
}

那么现在就可以建一个工厂类(Factory.java)来对实例类进行管理和创建了.

1
2
3
4
5
6
7
8
9
10
11
public  class  Factory {
     //静态工厂方法
     //多处调用,不需要实例工厂类
      public  static  Cat produceCat() {
             return  new  Cat();
         }
      public  static  Dog produceDog() {
             return  new  Dog();
         }
//当然也可以一个方法,通过传入参数,switch实现
}

使用:

1
2
3
4
5
6
Animal cat = Factory.produceCat();
cat.move();
//-----------------------------
Dog dog = Factory.produceDog();
dog.move();
dog.eatBone();

工厂模式在业界运用十分广泛,如果都用new来生成对象,随着项目的扩展,animal还可以生出许多其他儿子来,当然儿子还有儿子,同时也避免不了对以前代码的修改(比如加入后来生出儿子的实例),怎么管理,想着就是一团糟。

1
Animal cat = Factory.produceCat();

这里实例化了Animal但不涉及到Animal的具体子类(减少了它们之间的偶合联系性),达到封装效果,也就减少错误修改的机会。

Java面向对象的原则,封装(Encapsulation)和分派(Delegation)告诉我们:具体事情做得越多,越容易范错误,

一般来说,这样的普通工厂就可以满足基本需求。但是我们如果要新增一个Animal的实现类panda,那么必然要在工厂类里新增了一个生产panda的方法。就违背了 闭包的设计原则(对扩展要开放对修改要关闭) ,于是有了抽象工厂模式。

2.1 Abstract Factory(抽象工厂)

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
啥意思?就是把生产抽象成一个接口,每个实例类都对应一个工厂类(普通工厂只有一个工厂类),同时所有工厂类都继承这个生产接口。

生产接口Provider:

1
2
3
interface  Provider {
     Animal produce();
}

每个产品都有自己的工厂
CatFactory:

1
2
3
4
5
6
7
8
public  class  CatFactory  implements  Provider{
 
     @Override
     public  Animal produce() {
         // TODO Auto-generated method stub
         return  new  Cat();
     }
}

DogFactory:

1
2
3
4
5
6
7
8
public  class  DogFactory  implements  Provider{
 
     @Override
     public  Animal produce() {
         // TODO Auto-generated method stub
         return  new  Dog();
     }
}

产品生产:

1
2
3
Provider provider =  new  CatFactory();
Animal cat =provider.produce();
cat.move();

现在我们要加入panda,直接新建一个pandaFactory就行了,这样我们系统就非常灵活,具备了动态扩展功能。

2.1 Android中的Factory

比如AsyncTask的抽象工厂实现:

工厂的抽象:

1
2
3
4
public  interface  ThreadFactory {
//省略为备注
     Thread new Thread(Runnable r);
  }

产品的抽象(new Runnable就是其实现类):

1
2
3
4
    public  interface  Runnable {
//省略为备注
     public  abstract  void run();
  }

AsyncTask中工厂类的实现:

1
2
3
4
5
6
7
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());
     }
};

我们可以创建另外类似的工厂,生产某种专门的线程(多线程),非常容易扩展。
当然,android中的应用还有很多(比如BitmapFactory),有兴趣的小伙伴可以去扒一扒。

3. Adapter(适配器模式)

将一个类的接口转换成客户希望的另外一个接口。

我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。 怎么办?

使用Adapter,在这两种接口之间创建一个混合接口。

模式中的角色

需要适配的类(Adaptee):需要适配的类。

适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。

目标接口(Target):客户所期待的接口。可以是具体的或抽象的类,也可以是接口。

这里写图片描述

1
2
3
4
5
6
7
8
9
10
11
// 需要适配的类
class  Adaptee {
     public  void  specificRequest() {
         System.out.println( "需要适配的类" );
     }
}
 
// 目标接口
interface  Target {
     public  void  request();
}

实现方式:

①、对象适配器(采用对象组合方式实现)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 适配器类实现标准接口
class  Adapter  implements  Target{
     // 直接关联被适配类
     private  Adaptee adaptee;
 
     // 可以通过构造函数传入具体需要适配的被适配类对象
     public  Adapter (Adaptee adaptee) {
         this .adaptee = adaptee;
     }
 
     public  void  request() {
         // 这里是使用委托的方式完成特殊功能
         this .adaptee.specificRequest();
     }
}
 
// 测试类
public  class  Client {
     public  static  void  main(String[] args) {
         // 需要先创建一个被适配类的对象作为参数
         Target adapter =  new  Adapter( new  Adaptee());
         adapter.request();
     }
}

如果Target不是接口而是一个具体的类的情况,这里的Adapter直接继承Target就可以了。

②、类的适配器模式(采用继承实现)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 适配器类继承了被适配类同时实现标准接口
class  Adapter  extends  Adaptee  implements  Target{
     public  void  request() {
         super .specificRequest();
     }
}
 
// 测试类
     public  static  void  main(String[] args) {
         // 使用适配类
         Target adapter =  new  Adapter();
         adapter.request();
     }

如果Target和 Adaptee都是接口,并且都有实现类。 可以通过Adapter实现两个接口来完成适配。
还有一种叫PluggableAdapters,可以动态的获取几个adapters中一个。使用Reflection技术,可以动态的发现类中的Public方法。

优点

系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码,更好的扩展性。

缺点

过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现。如果不是必要,不要使用适配器,而是直接对系统进行重构。

3.1 Android中的Adapter

android中的Adapter就有很多了,这个大家都经常用。
Adapter是AdapterView视图与数据之间的桥梁,Adapter提供对数据的访问,也负责为每一项数据产生一个对应的View。

Adapter的继承结构

这里写图片描述

BaseAdapter的部分源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  abstract  class BaseAdapter  implements  ListAdapter, SpinnerAdapter {
     private  final  DataSetObservable mDataSetObservable =  new  DataSetObservable();
 
     public  boolean  hasStableIds() {
         return  false ;
     }
 
     public  void  registerDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.registerObserver(observer);
     }
 
     public  void  unregisterDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.unregisterObserver(observer);
     }

ListAdapter, SpinnerAdapter都是Target ,数据是Adaptee ,采用对象组合方式。

4. Chain of Responsibility(责任链模式)

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

编程中的小体现:

1
2
3
4
5
6
7
8
9
10
11
12
if (a< 10 ){
     ...
}
else  if (a< 20 ){
     ...
}
else  if (a< 30 ){
     ...
}
else {
     ...
}

程序必须依次扫描每个分支进行判断,找到对应的分支进行处理。

责任链模式的优点

可以降低系统的耦合度(请求者与处理者代码分离),简化对象的相互连接,同时增强给对象指派职责的灵活性,增加新的请求处理类也很方便;

责任链模式的缺点

不能保证请求一定被接收,且对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。
每次都是从链头开始,这也正是链表的缺点。

4.1 Android中的Chain of Responsibility

触摸、按键等各种事件的传递

这里写图片描述

有兴趣的可以看一下这篇文章View事件分发机制源码分析,我这就不多说了。

5. Observer(观察者模式)

有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的(依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。)。

观察者模式的组成

①抽象主题(Subject)

它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

②具体主题(ConcreteSubject)

将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

③抽象观察者(Observer)

为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

④具体观察者(ConcreteObserver)

实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。

这里写图片描述

言语苍白,上代码:

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
41
42
43
44
45
46
47
48
//抽象观察者
public  interface  Observer
{
   public  void  update(String str);
 
}
 
//具体观察者
public  class  ConcreteObserver  implements  Observer{
     @Override
     public  void  update(String str) {
         // TODO Auto-generated method stub
         System.out.println(str);
     }
}
 
//抽象主题
public  interface  Subject
{
     public  void  addObserver(Observer observer);
     public  void  removeObserver(Observer observer);
     public  void  notifyObservers(String str);
}
 
//具体主题
public  class  ConcreteSubject  implements  Subject{
     // 存放观察者
     private  List&lt;Observer&gt; list =  new  ArrayList&lt;Observer&gt;();
     @Override
     public  void  addObserver(Observer observer) {
         // TODO Auto-generated method stub
         list.add(observer);
     }
 
     @Override
     public  void  removeObserver(Observer observer) {
         // TODO Auto-generated method stub
         list.remove(observer);
     }
 
     @Override
     public  void  notifyObservers(String str) {
         // TODO Auto-generated method stub
         for (Observer observer:list){
             observer.update(str);
         }
     }
}

下面是测试类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
  * @author fanrunqi
  */
public  class  Test {
      public  static  void  main(String[] args) {
         //一个主题
          ConcreteSubject eatSubject =  new  ConcreteSubject();
          //两个观察者
          ConcreteObserver personOne =  new  ConcreteObserver();
          ConcreteObserver personTwo =  new  ConcreteObserver();
          //观察者订阅主题
          eatSubject.addObserver(personOne);
          eatSubject.addObserver(personTwo);
 
          //通知开饭了
          eatSubject.notifyObservers( "开饭啦" );
     }
}

“关于代码你有什么想说的?”
“没有,都在代码里了”
“(⊙o⊙)哦.....”

5.1 Android中的Observer

观察者模式在android中运用的也比较多,最熟悉的ContentObserver。

① 抽象类ContentResolver中(Subject)

注册观察者:

1
2
public  final  void  registerContentObserver(Uri uri,  boolean  notifyForDescendents,
         ContentObserver observer,  int  userHandle)

取消观察者:

1
public  final  void  unregisterContentObserver(ContentObserver observer)

抽象类ContentObserver中(Observer)

1
2
3
4
5
6
7
8
9
10
11
public  void  onChange( boolean  selfChange) {
      // Do nothing.  Subclass should override.
  }
 
public  void  onChange( boolean  selfChange, Uri uri,  int  userId) {
     onChange(selfChange, uri);
}
 
public  void  onChange( boolean  selfChange, Uri uri) {
     onChange(selfChange);
}

观察特定Uri引起的数据库的变化,继而做一些相应的处理(最终都调用的第一个函数).

② DataSetObserver,其实这个我们一直在用,只是没意识到。

我们再看到BaseAdapter的部分源码:

1
2
3
4
5
6
7
public  void  registerDataSetObserver(DataSetObserver observer) {
     mDataSetObservable.registerObserver(observer);
}
 
public  void  unregisterDataSetObserver(DataSetObserver observer) {
     mDataSetObservable.unregisterObserver(observer);
}

上面两个方法分别向向BaseAdater注册、注销一个DataSetObserver实例。

DataSetObserver 的源码:

1
2
3
4
5
6
7
8
9
10
public  abstract  class  DataSetObserver {
 
   public  void  onChanged() {
         // Do nothing
     }
 
     public  void  onInvalidated() {
         // Do nothing
     }
}

DataSetObserver就是一个观察者,它一旦发现BaseAdapter内部数据有变量,就会通过回调方法DataSetObserver.onChanged和DataSetObserver.onInvalidated来通知DataSetObserver的实现类。

6. Builder(建造者模式)

建造者模式:是将一个复杂的对象的构建与它的表示分离(同构建不同表示),使得同样的构建过程可以创建不同的表示。

  一个人活到70岁以上,都会经历这样的几个阶段:婴儿,少年,青年,中年,老年。并且每个人在各个阶段肯定是不一样的,世界上不存在两个人在人生的这5个阶段的生活完全一样,但是活到70岁以上的人,都经历了这几个阶段是肯定的。实际上这是一个比较经典的建造者模式的例子了。

将复杂的内部创建封装在内部,对于外部调用的人来说,只需要传入建造者和建造工具,对于内部是如何建造成成品的,调用者无需关心。

建造者模式通常包括下面几个角色:

① Builder:一个抽象接口,用来规范产品对象的各个组成成分的建造。

② ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建,在建造过程完成后,提供产品的实例。

③ Director:指导者,调用具体建造者来创建复杂对象的各个部分,不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

④ Product:要创建的复杂对象。

与抽象工厂的区别:在建造者模式里,有个指导者,由指导者来管理建造者,用户是与指导者联系的,指导者联系建造者最后得到产品。即建造模式可以强制实行一种分步骤进行的建造过程。

这里写图片描述

Product和产品的部分Part接口

1
2
public  interface  Product { }
public  interface  Part { }

Builder:

1
2
3
4
5
6
public  interface  Builder {
void  buildPartOne();
void  buildPartTwo();
 
Product getProduct();
}

ConcreteBuilder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//具体建造工具
public  class  ConcreteBuilder  implements  Builder {
Part partOne, partTwo;
 
public  void  buildPartOne() {
//具体构建代码
};
public  void  buildPartTwo() {
//具体构建代码
};
public  Product getProduct() {
//返回最后组装的产品
};
}

Director :

1
2
3
4
5
6
7
8
9
10
11
public  class  Director {
private  Builder builder;
 
public  Director( Builder builder ) {
this .builder = builder;
}
public  void  construct() {
builder.buildPartOne();
builder.buildPartTwo();
}
}

建造:

1
2
3
4
5
ConcreteBuilder builder =  new  ConcreteBuilder();
Director director =  new  Director(builder);
//开始各部分建造
director.construct();
Product product = builder.getResult();

优点:

客户端不必知道产品内部组成的细节。

具体的建造者类之间是相互独立的,对系统的扩展非常有利。

由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。

使用场合:

创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化。

要创建的复杂对象的算法,独立于该对象的组成部分,也独立于组成部分的装配方法时。

6.1 Android中的Builder

android中的Dialog就使用了Builder Pattern,下面来看看AlertDialog的部分源码。

1
2
3
4
5
6
7
8
9
public  static  class  Builder {
     private  final  AlertController.AlertParams P;
     private  int  mTheme;
 
     public  Builder(Context context,  int  theme) {
         P =  new  AlertController.AlertParams( new  ContextThemeWrapper(
                 context, resolveDialogTheme(context, theme)));
         mTheme = theme;
     }

AlertDialog的Builder 是一个静态内部类,没有定义Builder 的抽象接口。
对AlertDialog设置的属性会保存在Build类的成员变量P(AlertController.AlertParams)中。

Builder类中部分方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  Builder setTitle( int  titleId) {
     P.mTitle = P.mContext.getText(titleId);
     return  this ;
}
public  Builder setMessage( int  messageId) {
     P.mMessage = P.mContext.getText(messageId);
     return  this ;
}
 
public  Builder setPositiveButton(CharSequence text,  final  OnClickListener listener) {
     P.mPositiveButtonText = text;
     P.mPositiveButtonListener = listener;
     return  this ;
}

而show()方法会返回一个结合上面设置的dialog实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
         public  AlertDialog show() {
             AlertDialog dialog = create();
             dialog.show();
             return  dialog;
         }
     }
 
}
         public  AlertDialog create() {
             final  AlertDialog dialog =  new  AlertDialog(P.mContext, mTheme,  false );
             P.apply(dialog.mAlert);
             dialog.setCancelable(P.mCancelable);
             if (P.mCancelable) {
                 dialog.setCanceledOnTouchOutside( true );
             }
             dialog.setOnCancelListener(P.mOnCancelListener);
             dialog.setOnDismissListener(P.mOnDismissListener);
             if (P.mOnKeyListener !=  null ) {
                 dialog.setOnKeyListener(P.mOnKeyListener);
             }
             return  dialog;
         }

简单建造:

1
2
3
4
5
new  AlertDialog.Builder(context)
  .setTitle( "标题" )
  .setMessage( "消息框" )
  .setPositiveButton( "确定" ,  null )
  .show();

7. Memento(备忘录模式)

备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。

备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。

备忘录模式所涉及的角色有三个:

① Originator(发起人): 负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的哪些内部状态。

② Memento(备忘录): 负责存储Originnator对象的内部状态,并可防止Originator以外的其他对象访问备忘录Memento,备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。

③、 Caretaker(管理者):负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。

这里写图片描述

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public  class  Originator {
 
     private  String state;
     /**
      * 工厂方法,返回一个新的备忘录对象
      */
     public  Memento createMemento(){
         return  new  Memento(state);
     }
     /**
      * 将发起人恢复到备忘录对象所记载的状态
      */
     public  void  restoreMemento(Memento memento){
         this .state = memento.getState();
     }
 
     public  String getState() {
         return  state;
     }
 
     public  void  setState(String state) {
         this .state = state;
         System.out.println( "当前状态:" +  this .state);
     }
 
}
 
public  class  Memento {
 
     private  String state;
 
     public  Memento(String state){
         this .state = state;
     }
 
     public  String getState() {
         return state;
     }
 
     public  void  setState(String state) {
         this .state = state;
     }
 
}
 
public  class  Caretaker {
 
     private  Memento memento;
     /**
      * 备忘录的取值方法
      */
     public  Memento retrieveMemento(){
         return  this .memento;
     }
     /**
      * 备忘录的赋值方法
      */
     public  void  saveMemento(Memento memento){
         this .memento = memento;
     }
}

使用:

1
2
3
4
5
6
7
8
9
10
Originator o =  new  Originator();
Caretaker c =  new  Caretaker();
//改变负责人对象的状态
o.setState( "On" );
//创建备忘录对象,并将发起人对象的状态储存起来
  c.saveMemento(o.createMemento());
//修改发起人的状态
o.setState( "Off" );
//恢复发起人对象的状态
  o.restoreMemento(c.retrieveMemento());

不需要了解对象的内部结构的情况下备份对象的状态,方便以后恢复。

7.1 Android中的Memento

Activity的onSaveInstanceState和onRestoreInstanceState就是通过Bundle(相当于备忘录对象)这种序列化的数据结构来存储Activity的状态,至于其中存储的数据结构,这两个方法不用关心。

还是看一下源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected  void  onSaveInstanceState(Bundle outState) {
     outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
     Parcelable p = mFragments.saveAllState();
     if (p !=  null ) {
         outState.putParcelable(FRAGMENTS_TAG, p);
     }
     getApplication().dispatchActivitySaveInstanceState( this , outState);
}
protected  void  onRestoreInstanceState(Bundle savedInstanceState) {
     if (mWindow !=  null ) {
         Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
         if (windowState !=  null ) {
             mWindow.restoreHierarchyState(windowState);
         }
     }
}

8. Prototype(原型模式)

原型模式,能快速克隆出一个与已经存在对象类似的另外一个我们想要的新对象。
工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。

分为深拷贝和浅拷贝。深拷贝就是把对象里面的引用的对象也要拷贝一份新的对象,并将这个新的引用对象作为拷贝的对象引用(多读两遍)。

一般使用原型模式有个明显的特点,就是实现cloneable的clone()方法。

在Intent源码中:

1
2
3
4
@Override
public  Object clone() {
     return  new  Intent( this );
}

这里Intent通过实现Cloneable接口来实现原型拷贝。

9. Strategy(策略模式)

定义:有一系列的算法,将每个算法封装起来(每个算法可以封装到不同的类中),各个算法之间可以替换,策略模式让算法独立于使用它的客户而独立变化。

举例:
一个影碟机,你往里面插什么碟子,就能放出什么电影。
属性动画,设置不同的插值器对象,就可以得到不同的变化曲线。
返回值解析,传入什么样的解析器,就可以把二进制数据转换成什么格式的数据,比如String、Json、XML。

策略模式其实就是多态的一个淋漓精致的体现。

在android中不同Animation动画的实现,主要是依靠Interpolator的不同而实现的。

1
2
3
public  void  setInterpolator(Interpolator i) {
     mInterpolator = i;
}

10. Template(模板模式)

定义:定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。

实现流程已经确定,实现细节由子类完成。

生命周期对于我们都不陌生,它就是典型的Template模式,在具体流程确定的情况下,至于我们要复写生命周期那些方法,实现那些功能由继承activity的子类去具体实现。

关键在于必须有具体的执行流程,比如AsyncTask。

11. Proxy(代理模式)

定义:为其他对象提供一种代理以控制对这个对象的访问。
代理: 在出发点到目的地之间有一道中间层。

应用:Android跨进程通信方式 ,建议去了解一下Binder机制。

12. Interpreter(解释器模式)

定义语言的文法,并且建立一个解释器来解释该语言中的句子。

比如Android中通过PackageManagerService来解析AndroidManifest.xml中定义的Activity、service等属性。

13. State(状态模式)

行为是由状态来决定的,不同状态下有不同行为。

注意:状态模式的行为是平行的、不可替换的,策略模式的行为是彼此独立可相互替换的。

体现:不同的状态执行不同的行为,当WIFI开启时,自动扫描周围的接入点,然后以列表的形式展示;当wifi关闭时则清空。

14. Command(命令模式)

我们有很多命令,把它们放在一个下拉菜单中,用户通过先选择菜单再选择具体命令,这就是Command模式。

本来用户(调用者)是直接调用这些命令的,在菜单上打开文档,就直接指向打开文档的代码,使用Command模式,就是在这两者之间增加一个中间者,将这种直接关系拗断,同时两者之间都隔离,基本没有关系了。

显然这样做的好处是符合封装的特性,降低耦合度,有利于代码的健壮性 可维护性 还有复用性。Command是将对行为进行封装的典型模式,Factory是将创建进行封装的模式。

android底层逻辑对事件的转发处理就用到了Command模式。

15. Iterator(迭代模式)

提供一种方法顺序访问一个容器对象中的各个元素,而不需要暴露该对象的内部表示。

应用:

在Java中的Iterator类。

Android中的 Cursor。

1
cursor.moveToFirst();

16. Composite(组合模式)

将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

Android中View的结构是树形结构,每个ViewGroup包含一系列的View,而ViewGroup本身又是View。这是Android中非常典型的组合模式。

17. Flyweight(共享模式/享元模式)

定义:避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。

面向对象语言的原则就是一切都是对象,但是如果真正使用起来,有时对象数可能显得很庞大,比如,字处理软件,如果以每个文字都作为一个对象,几千个字,对象数就是几千,无疑耗费内存,那么我们还是要”求同存异”,找出这些对象群的共同点,设计一个元类,封装可以被共享的类,另外,还有一些特性是取决于应用(context),是不可共享的,这也Flyweight中两个重要概念内部状态intrinsic和外部状态extrinsic之分。

说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,很显然,在这里需要产生不同的新对象,所以Flyweight模式中常出现Factory模式。Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个Flyweight pool(模式池)来存放内部状态的对象。

Flyweight模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度。应用场合很多:比如你要从一个数据库中读取一系列字符串,这些字符串中有许多是重复的,那么我们可以将这些字符串储存在Flyweight池(pool)中。

在Android线程通信中,每次获取Message时调Message.obtain()其实就是从消息池中取出可重复使用的消息,避免产生大量的Message对象。

最后

那么问题来了,什么是设计模式?

这里写图片描述

设计模式是前辈、大牛在实际编程中对遇到的问题解决方案的抽象。

请尊重个人劳动成果,转载注明出处谢谢!
http://blog.youkuaiyun.com/amazing7/article/details/51719404

转载请注明:Android开发中文站 » Android 源码中的设计模式

Android源码设计模式探索与实战【面向对象六大基本原则】 IT行业,一直讲一句话,拼到最后都拼的是“内功”,而内功往往就是指我们处理问题的思路、经验、想法,而对于开发者来说,甚至对于产品也一样,都离不开一个“宝典”,就是设计模式。今天我们一起借助Android源码去探索一下设计的六大基本原则。同时结合我工作经验中的两个例子,来总结实践一下。 1.背景&定义 定义: 设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 理解: 设计模式是什么?设计模式(Desi. 阅读详情

相关推荐

Android面试题_安卓面经(23/30)设计模式源码案例

无论是做哪种编程语言的开发工作,过了新手期后,都需要了解设计模式,在安卓开发中也一样,本人曾在面试中让我列举安卓源码中设计模式的案例。

a763450633的博客 510

Android设计模式:Singleton模式

什么是单例模式? Singleton模式是一种软件设计模式 ,可确保一个类只有一个实例,并且该类提供了对其的全局访问点。 每当多个类或客户端请求该类时,它们都会获得该类的相同实例。 这个Singleton类可能负责实例化其自身,或者您可以将对象创建委托给factory类。 让我们以手机及其所有者为例。 一个电话通常由一个人拥有,而一个人可以拥有许多电话。 这些电话之一响起时,相同的所有者接...

代码教主 827

精通Android设计模式:深入Android源码解析

在软件工程领域,设计模式(Design Patterns)是为了解决特定问题而总结出的通用、可重用解决方案。在 Android 应用开发中,设计模式扮演着至关重要的角色,它们不仅提升了代码的可维护性、可扩展性,还优化了性能。掌握设计模式是Android开发者提升自己技能的重要一环。本章节将对Android系统中常见的设计模式进行介绍,为后续章节中对每个设计模式在Android中的应用和实现进行深入探讨。设计模式可以根据其解决的问题分为三种主要类别:创建型模式、结构型模式和行为型模式。

weixin_32480007的博客 1120

适配器模式(Adapter Pattern)

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许接口不兼容的类一起工作。适配器模式通过将类的接口转换为客户期望的另一个接口,使原本接口不兼容的类可以合作。

qq_34358193的博客 650

Gazebo仿真环境下的强化学习实现

实际上利用Gazebo进行强化学习无非是环境获取上的不同,Gazebo的环境控制需要使用ROS服务进行控制,状态可以通过Gazebo进行获取,同时某些必要数据需要从话题中获取,最重要的是组织获取 的数据(通过话题等)与控制Gazebo的仿真步骤之间的组合。强化学习的手段与传统算法无异,强化学习方法最重要的是要确定动作空间、状态空间、奖励空间,这三个空间是work的前提。在笔者自己的环境中,将获取里程计的话题以及获取激光点的数据替换成为了自己的本机的仿真环境匹配的话题。

Moresweet 猫甜 6451

从零开始:小鼠Bulk RNA-seq全流程实战指南

本文提供了一份详尽的小鼠Bulk RNA-seq全流程实战指南,涵盖从软件环境搭建、原始数据质控与清洗、序列比对、基因定量到下游差异表达分析与功能富集。内容面向生物信息学新手,通过清晰的代码示例和步骤解析,帮助读者系统掌握Bulk RNA-seq数据分析的核心技能,并产出可靠的生物学洞见。

lake5的博客 719

Android常见设计模式

首先一个重点就是**类的初始化得在一开始就弄,并且是由static修饰** 使用**static关键字创建类的静态变量时,这个变量会在类加载时被初始化**。**在java中,类加载只会发生1次**。因此,如果使用static关键字创建单例对象,那么在类加载时就会创建单例对象。 但是饿汉模式是有一个缺点,就是这个变量会在类加载时被初始化,如果没用过这个实例的话,就容易造成内存的浪费。 这就不符合**懒加载**的效果

m0_61130325的博客 8797

使用 NTLite 来定制专属的官方 windows 镜像

移除掉不想要的一些自带的应用,比如 Xbox,office 啥的,这个就根据自己的实际需求来选择,备注基本都是有解释这个应用的作用。win 11 的右键展示不喜欢,更喜欢 win10 的,但是需要修改注册表,这里直接把下面的命令写到后期任务里面。NTLite 的自动保存会话功能会保留操作过的配置,是一个 xml 文件,可以在下次升级镜像版本的时候,导入配置。关闭 windows defender,不关会有这个提示,点是,就会跳到对应的界面。勾选创建 iso,配置 iso 镜像的名字,然后点开始。

以梦为马|越骑越傻 3336

Android常用设计模式(小白必看)

Java/Kotlin的五大最常用设计模式,通俗易懂

zhoujun798的博客 3584

Kettle下载与安装教程【保姆版】

Kettle简介 Kettle最早是一个开源的ETL工具,全称为KDE Extraction, Transportation, Transformation and Loading Environment。后来Kettle重命名为Pentaho Data Integration 。 它由Java开发,支持跨平台运行,其特性包括:支持100%无编码、拖拽方式开发ETL数据管道;可对接包括传统数据库、文件、大数据平台、接口、流数据等数据源;支持ETL数据管道加入机器学习算法。 主要功能 Pentaho D

weixin_43407520的博客 12万+

哨兵2植被参数反演避坑指南:SNAP中10m/20m分辨率选择与缺失波段处理

本文深入解析了使用SNAP软件进行哨兵2号植被参数反演时的关键操作与决策。核心在于理解SNAP生物物理处理器NNET10m与NNET20m的架构差异,根据是否需要反演冠层叶绿素含量(Cab)等参数,明智选择10米或20米分辨率工作流。文章详细指导了大气校正、波段重采样及处理L2A数据中B01波段“缺失”等常见问题的解决方案,为生态监测与精准农业应用提供清晰的避坑指南和完整实战流程。

wdx01234567的博客 262

Android源码中的部分设计模式

Android源码中广泛使用了多种设计模式,以解决不同场景下的架构设计需求。以下是几个常见的设计模式及其在Android中的应用: 1. 单例模式 (Singleton Pattern) 应用: 单例模式确保一个类只有一个实例,并提供一个全局访问点。 示例: Context: Context 类的实现(尤其是 ApplicationContext)经常以单例的方式使用,以确保全局唯一的应用上下文实例。 ActivityManager: ActivityManager 是 Android 中管理应用进程和活

qq_34358193的博客 1358

DMA+Timer 生成 PWM 波形错位问题分析与解决

本文深入分析了DMA与Timer协同生成PWM波形时出现的错位问题,揭示了DMA传输启动时机与定时器溢出中断的微妙关系。通过占空比强制清零法和预装载值调校技巧,提供了有效的解决方案,并总结了PWM+DMA配置的最佳实践,帮助开发者避免类似问题。

weixin_29191081的博客 349

Android 源码设计模式总结

Android 源码设计模式总结 设计模式可以按照创建型设计模式、结构型设计模式、行为型设计模式分为 3 类,共 23 种设计模式。 创建型设计模式 创建型设计模式共有 5 种。 工厂方法 Factory Method Android 源码的工厂方法模式 抽象工厂 Abstract Factory Android 源码的抽象工厂模式 建造者 Builder Android 源码的建造者模式 原型 ...

okclouderx的博客 262

红队攻防渗透技术实战流程:云安全之云原生安全:特权模式和挂载模式

红队云攻防实战1. 什么是云 1. 什么是云

HACKONE的博客 575

Python爬虫实战:基于最新技术爬取国家企业信用信息公示系统数据

本文将详细介绍如何使用Python最新技术栈构建一个高效、稳定的国家企业信用信息公示系统爬虫。我们将从爬虫基础知识讲起,逐步深入到反爬机制应对、数据解析与存储等高级话题,最终实现一个完整的爬虫系统。文章包含大量实战代码示例,适合中高级Python开发者学习参考。网络爬虫(Web Crawler)是一种自动获取网页内容的程序,广泛应用于搜索引擎、数据分析和商业情报收集等领域。通用爬虫:如搜索引擎爬虫,广泛抓取互联网公开信息聚焦爬虫:针对特定领域或网站的数据采集增量式爬虫:只抓取更新内容,减少资源消耗。

2201_76125261的博客 2410

《Android源码设计模式解析与实战》PDF下载

《Android源码设计模式解析与实战》PDF下载 【下载地址】Android源码设计模式解析与实战PDF下载 《Android源码设计模式解析与实战》是一本深度剖析Android源代码设计模式的实用指南。通过解析Android源码中的经典设计模式,并结合实际案例,本书生动展示了如何在开发中应用这些模式。无论您是对And...

gitblog_06774的博客 552

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

专访何红辉:谈谈Android源码中的设计模式

最近Android 6.0版本的源代码开放下载,刚好分析Android源码的技术书籍《Android源码设计模式解析与实战》上市,我们邀请到它的作者何红辉,来谈谈Android源码中的设计模式,以及近期Android开发中的一些热点话题。\\受访嘉宾介绍:\何红辉(@MrSimp1e),前友盟Android工程师,活跃于国内各大技术社区,热爱开源,热爱技术,热爱分享。Android开源库Andro...

weixin_33716941的博客 220

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Camera安卓源码剖析-源码中的设计模式实例

环境:Android 7.1.1 Source Code —— Camera2 策略模式、抽象工厂模式、观察者模式、装饰者模式

我肚子饿了 816

初级开发工程师要懂的六大原则和设计模式,中级安卓开发更需要懂得如何融入Android源码灵活架构业务场景

Android开发中的设计原则与模式 六大SOLID原则在Android开发中广泛应用:单一职责原则(如Activity与Fragment分工)、开闭原则(通过继承扩展View)、里氏替换原则(如Window继承体系)、接口隔离原则(分离点击监听器)、依赖倒置原则(如Context抽象)和迪米特法则(Intent机制减少耦合)。组合优于继承原则体现在ViewGroup等设计中。 常用设计模式包括:单例模式(系统服务管理)、观察者模式(LiveData数据同步)、工厂模式(Bitmap创建)、适配器模式(Re

da_ma_dai的博客 775

谈谈23种设计模式在Android源码及项目中的应用

谈谈23种设计模式在Android源码及项目中的应用 本文首发于个人博客:Lam's Blog - 谈谈23种设计模式在Android源码及项目中 的应用,文章由MarkDown语法编写,可能不同平台渲染效果不一,如果有存在排 版错误图片无法显示等问题,烦请移至个人博客,如果个人博客无法访问可以留 言告诉我,转载请声明个人博客出处,谢谢。 本文将结合实际谈谈23种设计模式,每种设计模式涉及 定义:抽象化的定义与通俗的描述,尽量说明清楚其含义与应用场景 示例:如果项目中有使用过该模式,则会给出项目中的代码,否

idaretobe的专栏 533

Android源码设计模式分析一期发布

简述设计模式已经成为开发人员最重要的技能之一,它们能够让你优雅、简单、灵活地解决开发中遇到的设计难题,让你的软件系统具有更好的可扩展性、灵活性,在特定场景之下让你的软件系统实现拥抱变化。但设计模式运用在Android上的书籍并不多,Android本身又是开源,那么剖析Android源码中的设计模式必定是我们学习设计模式的一个非常好的渠道。我们在大型系统中学习设计模式的运用,领悟它的设计思考、灵活运用

Mr.Simple的专栏 2万+

Android源码设计模式分析项目

原文链接:https://github.com/simple-android-framework/android_design_patterns_analysisAndroid源码设计模式分析开源项目该系列文章已经重新深度整理并出版该系列文章已经根据技术发展、实战需求以及读者您的反馈重写所有章节,并且加入更加深入的核心机制分析以及模式在Android开发中的实战,以便帮助大家更系统的学习。书籍已经出

JackChan 2378
上一篇: Android工程师面试题大全
下一篇: Android 进程保活
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值