Android 经常使用设计模式

Posted gccbuaa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 经常使用设计模式相关的知识,希望对你有一定的参考价值。

由于项目变更的频繁性,作为一名程序猿,我们须要掌握设计模式的必要性。就不言而喻~~。以下就是一些我自己学习的设计模式总结。
接下来,主要是针对几个比較经常使用模式进行解说,主要是以下几种:

  • 观察者模式
  • 适配器模式
  • 代理模式
  • 工厂模式
  • 单例模式
  • 命令模式

1.观察者模式(Observer Pattern)
释义:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同一时候监听某一个主题对象,这个主题对象在状态上发生变化时,会通知全部观察者对象,使他们能够自己主动更新自己。
故事理解:观察者想知道公司全部MM的情况,仅仅要增加公司的MM情报邮件组即可了,tom负责搜集情报,当发现新情报时,不用一个一个通知我们,直接公布给邮件组。我们作为订阅者(观察者)就能够及时收到情报啦。
常见实例:1.BaseAdapter.registerDataSetObserver和BaseAdapter.unregisterDataSetObserver双方法来向BaseAdater注冊、注销一个DataSetObserver ; 2.使用ContentObserver去监听数据库变化。


适用场景:1.当对一个对象的改变须要同一时候改变其它对象,而不知道详细有多少对象有待改变。2.当一个对象必须通知其它对象。而它又不能假定其它对象是谁.

观察者模式主要有观察者和被观察者2个对象。在该模式中。Observable表示被观察者,这个对象是一个抽象类。仅仅能被继承。 Observer表示观察者,他是一个接口。所以观察者能够有多个。实现了该接口的类都是属于观察者。
这是网上一个生动仔细的demo:
被观察者:

public class MyPerson extends Observable {

    private int age;
    private String name;
    private String sax;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        setChanged();
        notifyObservers();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        setChanged();
        notifyObservers();
    }

    public String getSax() {
        return sax;
    }

    public void setSax(String sax) {
        this.sax = sax;
    }

    @Override
    public String toString() {
        return "MyPerson [age=" + age + ", name=" + name + ", sax=" + sax + "]";
    }
}

MyPerson是被观察者,类中调用了setChange()以及notifyObservers()两个方法。前者是告知数据改变,后者是发送信号通知观察者。

观察者:

public class MyObserver implements Observer {

    private int i;
    private MyPerson myPerson;//观察的对象

    public MyObserver(int i){
        System.out.println("我是观察者---->" + i);
        this.i = i;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    public MyPerson getMyPerson() {
        return myPerson;
    }

    public void setMyPerson(MyPerson myPerson) {
        this.myPerson = myPerson;
    }

    @Override
    public void update(Observable observable, Object data) {
        System.out.println("观察者---->"+ i +"得到更新!");
        this.myPerson = (MyPerson)observable;
        System.out.println(((MyPerson)observable).toString());
    }

}

观察者须要实现Observer接口,当中仅仅有一个update方法。当观察者收到 (被观察者)的通知信号。就会执行该动作。

详细demo源代码以及实现效果可点连接

2.适配器模式(Adapter Pattern)
释义:把一个类的接口变换成client所期待的还有一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。

适配类能够依据參数返还一个合适的实例给client。


故事理解:在朋友聚会上碰到了一个美女Sarah。从香港来的,可我不会说粤语。她不会说普通话,仅仅好求助于我的朋友kent了,他作为我和Sarah之间的Adapter,让我和Sarah能够相互交谈了(也不知道他会不会耍我)。
常见实例:ListView用于显示列表数据,可是作为列表数据集合有非常多形式。有Array,有Cursor,我们须要相应的适配器作为桥梁,处理相应的数据(并能形成ListView所须要的视图)。
适用场景:1.业务的接口与工作的类不兼容,(比方:类中缺少实现接口的某些方法)但又须要两者一起工作。2. 在现有接口和类的基础上为新的业务需求提供接口。

适配器模式分为类适配器模式和对象适配器模式。

关于类适配模式。由于java的单继承,所以在已继承一个类时。另外的仅仅能是接口,须要手动实现相应的方法,这样在client就能够创建任一种符合需求的子类。来实现详细功能。而第二种对象适配器,它不是使用继承再实现的方式,而是使用直接关联,或者称为托付的方式,详细可见该博客详细介绍适配器模式(Adapter):类适配器、对象适配器

接下来就以ListView与ArrayAdapter来解说下
ListAdapter:

public interface ListAdapter {
    public int getCount();
    Object getItem(int position);
    long getItemId(int position);
    View getView(int position, View convertView, ViewGroup parent);
    boolean isEmpty();
}

ListView作为一个client,所须要的目标接口就是ListAdapter,包括getCount(),getItem(),getView()等几个方法。为了兼容List< T >数据类型的数据源。专门定义了ArrayAdapter适配器,说白了。就是针对目标接口对数据源进行兼容修饰。

抽象类BaseAdapter,省略了其它代码,这里仅仅列出两个方法:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    // ... ...
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getView(position, convertView, parent);
    }
    public boolean isEmpty() {
        return getCount() == 0;
    }
}

ArrayAdapter对List< T >进行封装成ListAdapter的实现,满足ListView的调用:

public class ArrayAdapter<T> extends BaseAdapter implements Filterable {
    private List<T> mObjects;
    //我仅仅列出这一个构造函数。大家懂这个意思即可
    public ArrayAdapter(Context context, int textViewResourceId, T[] objects) {
        init(context, textViewResourceId, 0, Arrays.asList(objects));
    }

    private void init(Context context, int resource, int textViewResourceId, List<T> objects) {
        mContext = context;
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mResource = mDropDownResource = resource;
        mObjects = objects; //引用对象,也是表达了组合优于继承的意思
        mFieldId = textViewResourceId;
    }
    public int getCount() {
        return mObjects.size();
    }

   public T getItem(int position) {
        return mObjects.get(position);
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mResource);
    }
    // ... ...
}

我们就如此成功的把List< T > 作为数据源以ListView想要的目标接口的样子传给了ListView。这事实上也是对象适配器的一种。

3.代理模式(Proxy Pattern)
释义: 通过引入一个新的对象来实现对真实对象的操作或将新的对象作为真实对象的一个替身,这种实现机制是代理模式(为其它对象提供一种代理以控制对这个对象的訪问).
故事理解:校园代理是为他相应的上司作代理,而这个校园代理的工作就是訪问校园中的学生。比如对学生进行问卷之类的事。

学生就是官方说法中的其它对象,校园代理的上司就通过控制这个校园代理来控制对学生的訪问。
常见实例:ActivityManagerProxy类就是一个代理。它是ActivityManagerNative的代理,也就是说ActivityManagerProxy是所说的Proxy类。而ActivityManagerNative就相当于“上司角色“类,它们都有一个共同拥有的接口IActivityManager。ActivityManager。它相当于代理模式的client。在这个类中,能够看到大量的getxxx函数,这些函数,都会调用到ActivityManagerNative类的getDefault()方法,而该方法会获得一个共用的单例的IActivityManager引用。然后通过多态来调用代理中的实现
适用场景:代理模式的应用场合分几种:远程代理,虚拟代理,安全代理等,详细可见为别人做嫁衣—-代理模式

请看以下一张结构图(网上看到的一个仔细生动的样例):

技术分享

Subject类:定义了RealSubject和Proxy的共用接口,这样就能够在不论什么 使用RealSubject的地方都能够用Proxy。
RealSubject类:定义Proxy所代表的真实实体。
Proxy类:保存一个引用使得代理能够訪问实体,并提供一个与Subject的接口同样的接口。这样代理就能够用来替代实体。

接下来,我们来实现该模式:
1.Subject类 :Image.java

/**
 * Subject类
 */
public abstract class Image {

    public abstract void displayImage();

}

2.RealSubject类:RealImage.java


import com.andyidea.patterns.subject.Image;  

/**  
 * RealSubject类  
 */  
public class RealImage extends Image {  
    private String filename;  
    public RealImage(String filename) {   
        this.filename = filename;  
        loadImageFromDisk();  
    }  

    private void loadImageFromDisk() {  

        System.out.println("Loading   " + filename);  
    }  

    @Override  
    public void displayImage() {  

        System.out.println("Displaying " + filename);   
    }  

} 

3.proxy类:ProxyImage.java

import com.andyidea.patterns.realsubject.RealImage;
import com.andyidea.patterns.subject.Image;

/**
 * Proxy类
 */
public class ProxyImage extends Image {
    private String filename;
    private Image image;

    public ProxyImage(String filename) { 
        this.filename = filename; 
    }

    @Override
    public void displayImage() {

        if(image == null){
            image = new RealImage(filename);
        }
        image.displayImage();
    }

}

4.client測试类:ProxyClient.java

import com.andyidea.patterns.proxy.ProxyImage;
import com.andyidea.patterns.subject.Image;

/**
 * 代理模式client測试类
 */
public class ProxyClient {

    public static void main(String[] args) {
        System.out.println("Welcome to my Blog!" +"\n" 
                   +"Proxy Patterns." +"\n"
                   +"-------------------------------");

        Image mImage1 = new ProxyImage("My.Image1");
        Image mImage2 = new ProxyImage("My.Image2");

        mImage1.displayImage();
        mImage2.displayImage();
    }
}

执行结果例如以下:

        Welcome to my Blog!  
        Proxy Patterns
        ------------------------------- 
        Loading   My.Image1 
        Displaying My.Image1 
        Loading   My.Image2  
        Displaying My.Image2

总结来说,代理类就是对实体保存一个引用。同一时候也实现了实体一样的接口方法,这样。就能够替代实体了!!

以上就是观察者模式。适配器模式,代理模式的认识,接下来会在 Android 经常使用设计模式(二)里,继续对余下的三种模式进行阐述。




















以上是关于Android 经常使用设计模式的主要内容,如果未能解决你的问题,请参考以下文章

Android Reorder Fragment Backstack

Android课程---Android Studio使用小技巧:提取方法代码片段

js经常用到的代码片段

[Android]Fragment源代码分析 事务

如何使用 Android 片段?

片段覆盖整个android编辑屏幕