Android中常用的设计模式_android中常用的设计模式,说三个比较高级的?-程序员宅基地

技术标签: 平时笔记  android  android设计模式  移动开发  设计模式  

对于开发来说,设计模式是必不可少的,就像是一个项目的架海紫金梁,而且熟悉常用的设计模式可以有助于我们研读源码。好,废话不多说,开始介绍

1> 单例

不想再说了,如果还有人不会,我叫他大爷。

大爷,您好!

概念:确保一个类只有一个实例,并且自行实例化并向整个系统提供整个实例

优点:

1,对于那些耗内存的类,只实例化一次,大大提高性能,尤其是移动开发中

2,程序运行中,始终保持只有一个实例在内存中

public class Singleton {  
    private static volatile Singleton instance = null;  

    private Singleton(){  
    }  

    public static Singleton getInstance() {  
        if (instance == null) {  
            synchronized (Singleton.class) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }  
}  

构造函数私有化,定义静态函数获得实例就不多说了,这里着重说一下volatile:

volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从内存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.(首先我们要先意识到有这样的现象,编译器为了加快程序运行的速度,对一些变量的写操作会先在寄存器或者是CPU缓存上进行,最后才写入内存.
而在这个过程,变量的新值对其他线程是不可见的.而volatile的作用就是使它修饰的变量的读写操作都必须在内存中进行!)

再就是这个双重判断null :

这是因为如果线程A进入了该代码,线程B 在等待,这是A线程创建完一个实例出来后,线程B 获得锁进入同步代码,实例已经存在,木有必要再创建一个,所以双重判断有必要。

哎,不说不说的又写了这么多。

Android中 用到的地方很多,比如Android-Universal-Image-Loader中的单例,EventBus中的单例

最后给出一个管理我们activity的类,可以作为一个简单工具类

public class ActivityManager {  

    private static volatile ActivityManager instance;  
    private Stack<Activity> mActivityStack = new Stack<Activity>();  

    private ActivityManager(){  

    }  

    public static ActivityManager getInstance(){  
        if (instance == null) {  
        synchronized (ActivityManager.class) {  
            if (instance == null) {  
                instance = new ActivityManager();  
            }  
        }  
        return instance;  
    }  

    public void addActicity(Activity act){  
        mActivityStack.push(act);  
    }  

    public void removeActivity(Activity act){  
        mActivityStack.remove(act);  
    }  

    public void killMyProcess(){  
        int nCount = mActivityStack.size();  
        for (int i = nCount - 1; i >= 0; i--) {  
            Activity activity = mActivityStack.get(i);  
            activity.finish();  
        }  

        mActivityStack.clear();  
        android.os.Process.killProcess(android.os.Process.myPid());  
    }  

2> Builder 模式

还是按部就班的先说一下定义,网上的定义,

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

是不是上来先读了两遍,然后发现,没读懂,没关系,大家基本都没读懂,概念就是比较抽象的,让大家很难理解的,如果简单从这个一个概念就搞懂了这个模式的话,那就不用费力的去查资料整理后边的东西了。
这里我们通过一个栗子来引出Build模。假设有一个Person类,他的一些属性可以为null,可以通过这个类来构架一大批人

public class Person {  
    private String name;  
    private int age;  
    private double height;  
    private double weight;  

    public String getName() {  
        return name;  
    }  

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

    public int getAge() {  
        return age;  
    }  

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

    public double getHeight() {  
        return height;  
    }  

    public void setHeight(double height) {  
        this.height = height;  
    }  

    public double getWeight() {  
        return weight;  
    }  

    public void setWeight(double weight) {  
        this.weight = weight;  
    }  
}  

然后为了方便,你可能会写这么一个构造函数来穿传属性

public Person(String name, int age, double height, double weight) {  
    this.name = name;  
    this.age = age;  
    this.height = height;  
    this.weight = weight;  
} 

或者为了更方便还会写一个空的构造函数

public Person() {  
}  

有时候还会比较懒,只传入某些参数,又会来写这些构造函数

public Person(String name) {  
    this.name = name;  
}  

public Person(String name, int age) {  
    this.name = name;  
    this.age = age;  
}  

public Person(String name, int age, double height) {  
    this.name = name;  
    this.age = age;  
    this.height = height;  
} 

于是就可以来创建各种需要的类

Person p1=new Person();  
Person p2=new Person("张三");  
Person p3=new Person("李四",18);  
Person p4=new Person("王五",21,180);  
Person p5=new Person("赵六",17,170,65.4);  

其实这种写法的坏处在你写的过程中想摔键盘的时候就该想到了,既然就是一个创建对象的过程,怎么这么繁琐,并且构造函数参数过多,其他人创建对象的时候怎么知道各个参数代表什么意思呢,这个时候我们为了代码的可读性,就可以用一下Builder模式了
给Person类添加一个静态Builder类,然后修改Person的构造函数,如下,

public class Person {  
    private String name;  
    private int age;  
    private double height;  
    private double weight;  

    privatePerson(Builder builder) {  
        this.name=builder.name;  
        this.age=builder.age;  
        this.height=builder.height;  
        this.weight=builder.weight;  
    }  
    public String getName() {  
        return name;  
    }  

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

    public int getAge() {  
        return age;  
    }  

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

    public double getHeight() {  
        return height;  
    }  

    public void setHeight(double height) {  
        this.height = height;  
    }  

    public double getWeight() {  
        return weight;  
    }  

    public void setWeight(double weight) {  
        this.weight = weight;  
    }  

    static class Builder{  
        private String name;  
        private int age;  
        private double height;  
        private double weight;  
        public Builder name(String name){  
            this.name=name;  
            return this;  
        }  
        public Builder age(int age){  
            this.age=age;  
            return this;  
        }  
        public Builder height(double height){  
            this.height=height;  
            return this;  
        }  

        public Builder weight(double weight){  
            this.weight=weight;  
            return this;  
        }  

        public Person build(){  
            return new Person(this);  
        }  
    }  
}  

从上边代码我们可以看到我们在Builder类中定义了一份跟Person类一样的属性,通过一系列的成员函数进行赋值,但是返回的都是this,最后提供了一个build函数来创建person对象,对应的在Person的构造函数中,传入了Builder对象,然后依次对自己的成员变量进行赋值。此外,Builder的成员函数返回的都是this的另一个作用就是让他支持链式调用,使代码可读性大大增强
于是我们就可以这样创建Person对象

Person.Builder builder=new Person.Builder();  
Person person=builder  
        .name("张三")  
        .age(18)  
        .height(178.5)  
        .weight(67.4)  
        .build();  

是不是有那么点感觉了呢
Android中大量地方运用到了Builder模式,比如常见的对话框创建

AlertDialog.Builder builder=new AlertDialog.Builder(this);  
AlertDialog dialog=builder.setTitle("标题")  
        .setIcon(android.R.drawable.ic_dialog_alert)  
        .setView(R.layout.myview)  
        .setPositiveButton(R.string.positive, new DialogInterface.OnClickListener() {  
            @Override  
            public void onClick(DialogInterface dialog, int which) {  

            }  
        })  
        .setNegativeButton(R.string.negative, new DialogInterface.OnClickListener() {  
            @Override  
            public void onClick(DialogInterface dialog, int which) {  

            }  
        })  
        .create();  
dialog.show();  

其实在java中StringBuilder 和StringBuffer都用到了Builder模式,只不过是稍微简单一点了

Gson中的GsonBuilder

GsonBuilder builder=new GsonBuilder();  
Gson gson=builder.setPrettyPrinting()  
        .disableHtmlEscaping()  
        .generateNonExecutableJson()  
        .serializeNulls()  
        .create();  

网络框架OKHttp

Request.Builder builder=new Request.Builder();  
Request request=builder.addHeader("","")  
    .url("")  
    .post(body)  
    .build();  

可见大量框架运用了Builder 设计模式,总结一下吧:
定义一个静态内部类Builder,内部成员变量跟外部一样

Builder通过一系列方法给成员变量赋值,并返回当前对象(this)

Builder类内部提供一个build方法方法或者create方法用于创建对应的外部类,该方法内部调用了外部类的一个私有化构造方法,该构造方法的参数就是内部类Builder

外部类提供一个私有化的构造方法供内部类调用,在该构造函数中完成成员变量的赋值


3 > 观察者模式

二话不说,上来就是定义

定义对象间的一种一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都能得到通知并被自动更新
这个好像还好理解那么一点点,不过还是先来讲个情景,

天气预报的短信服务,一旦付费订阅,每次天气更新都会向你及时发送

其实就是我们无需每时每刻关注我们感兴趣的东西,我们只需要订阅它即可,一旦我们订阅的事务有变化了,被订阅的事务就会即时的通知我们

我们来看一下观察者模式的组成:

观察者,我们称它为Observer,有时候我们也称它为订阅者,即Subscriber
被观察者,我们称它为Observable,即可以被观察的东西,有时候还会称之为主题,即Subject
至于观察者模式的具体实现,java里为我们提供了Observable类和Observer接口供我们快速实现该模式,但是这里为了加深印象,不用这个两个类
我们来模拟上边的场景,先定义一个Weather的类

public class Weather {  
    private String description;  

    public Weather(String description) {  
        this.description = description;  
    }  

    public String getDescription() {  
        return description;  
    }  

    public void setDescription(String description) {  
        this.description = description;  
    }  

    @Override  
    public String toString() {  
        return "Weather{" +  
                "description='" + description + '\'' +  
                '}';  
    }  
}  

然后定义我们的被观察着,我们希望它能够通用,所以定义成泛型,内部应该暴露出register和unRegister供观察者订阅和取消订阅,至于观察者的保存,我们用ArrayList即可,另外,当主题发生变化的时候,需要通知观察者来做出响应,还需要一个notifyObservers方法,具体实现如下:

public class Observable<T> {  
    List<Observer<T>> mObservers = new ArrayList<Observer<T>>();  

    public void register(Observer<T> observer) {  
        if (observer == null) {  
            throw new NullPointerException("observer == null");  
        }  
        synchronized (this) {  
            if (!mObservers.contains(observer))  
                mObservers.add(observer);  
        }  
    }  

    public synchronized void unregister(Observer<T> observer) {  
        mObservers.remove(observer);  
    }  

    public void notifyObservers(T data) {  
        for (Observer<T> observer : mObservers) {  
            observer.onUpdate(this, data);  
        }  
    }  

}  

而我们的观察者只需要实现一个观察者的接口Observer,该接口也是泛型的

public interface Observer<T> {  
    void onUpdate(Observable<T> observable,T data);  
}  

一旦订阅的主题发生了变化,就会调用该接口
用一下,我们定义一个天气变化的主题,也就是被观察者,再定义两个观察者来观察天气的变化,一旦变化了就打印出天气的情况,注意,一定要用register方法来注册,否则观察者收不到变化的信息,而一旦不感兴趣,就可以调用unregister方法

public class Main {  
    public static void main(String [] args){  
        Observable<Weather> observable=new Observable<Weather>();  
        Observer<Weather> observer1=new Observer<Weather>() {  
            @Override  
            public void onUpdate(Observable<Weather> observable, Weather data) {  
                System.out.println("观察者1:"+data.toString());  
            }  
        };  
        Observer<Weather> observer2=new Observer<Weather>() {  
            @Override  
            public void onUpdate(Observable<Weather> observable, Weather data) {  
                System.out.println("观察者2:"+data.toString());  
            }  
        };  

        observable.register(observer1);  
        observable.register(observer2);  


        Weather weather=new Weather("晴转多云");  
        observable.notifyObservers(weather);  

        Weather weather1=new Weather("多云转阴");  
        observable.notifyObservers(weather1);  

        observable.unregister(observer1);  

        Weather weather2=new Weather("台风");  
        observable.notifyObservers(weather2);  

    }  
}  

输出也灭有问题

观察者1:Weather{description=’晴转多云’}
观察者2:Weather{description=’晴转多云’}
观察者1:Weather{description=’多云转阴’}
观察者2:Weather{description=’多云转阴’}
观察者2:Weather{description=’台风’}

好,我们来看一下在Android中的应用,从最简单的开始,Button的点击事件

Button btn=new Button(this);  
btn.setOnClickListener(new View.OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        Log.e("TAG","click");  
    }  
});  

严格意义来说,这只能算是一个回调,但是我们可以把它看做是一个一对一的观察者模式,其实,只要是set系列的设置监听事件的方法最多都只能算是一种回调,但是一些监听器是通过add添加的,这些就观察者模式了比如,RecyclerView的addScrollListener方法

private List<OnScrollListener> mScrollListeners;  
public void addOnScrollListener(OnScrollListener listener) {  
    if (mScrollListeners == null) {  
        mScrollListeners = new ArrayList<OnScrollListener>();  
    }  
    mScrollListeners.add(listener);  
}  
public void removeOnScrollListener(OnScrollListener listener) {  
    if (mScrollListeners != null) {  
        mScrollListeners.remove(listener);  
    }  
}  
public void clearOnScrollListeners() {  
    if (mScrollListeners != null) {  
        mScrollListeners.clear();  
    }  
}  

然后有滚动事件时就触发观察者方法进行回调

public abstract static class OnScrollListener {  
    public void onScrollStateChanged(RecyclerView recyclerView, int newState){}  
    public void onScrolled(RecyclerView recyclerView, int dx, int dy){}  
}  

void dispatchOnScrolled(int hresult, int vresult) {  
    //...  
    if (mScrollListeners != null) {  
        for (int i = mScrollListeners.size() - 1; i >= 0; i--) {  
            mScrollListeners.get(i).onScrolled(this, hresult, vresult);  
        }  
    }  
}  
void dispatchOnScrollStateChanged(int state) {  
    //...  
    if (mScrollListeners != null) {  
        for (int i = mScrollListeners.size() - 1; i >= 0; i--) {  
            mScrollListeners.get(i).onScrollStateChanged(this, state);  
        }  
    }  
}  

另外广播机制,本质也是观察者模式
调用registerReceiver方法注册广播,调用unregisterReceiver方法取消注册,之后使用sendBroadcast发送广播,之后注册的广播会受到对应的广播信息,这就是典型的观察者模式

开源框架EventBus也是基于观察者模式的,

观察者模式的注册,取消,发送事件三个典型方法都有

EventBus.getDefault().register(Object subscriber);  
EventBus.getDefault().unregister(Object subscriber);  

EventBus.getDefault().post(Object event);  

比较重量级的库RxJava,创建一个被观察者

Observable<String> myObservable = Observable.create(    
    new Observable.OnSubscribe<String>() {    
        @Override    
        public void call(Subscriber<? super String> sub) {
        
            sub.onNext("Hello, world!");    
            sub.onCompleted();    
        }    
    }    
);  

创建一个观察者,也就是订阅者

Subscriber<String> mySubscriber = new Subscriber<String>() {    
    @Override    
    public void onNext(String s) { System.out.println(s); }    

    @Override    
    public void onCompleted() { }    

    @Override    
    public void onError(Throwable e) { }    
};  

观察者进行事件的订阅

myObservable.subscribe(mySubscriber);  

4 > 策略模式

定义:策略模式定义了一系列算法,并将每一个算法封装起来,而且使他们可以相互替换,策略模式让算法独立于使用的客户而独立改变

乍一看也没看出个所以然来,还是举个栗子,

最常见的就是关于出行旅游的策略模式,出行方式有很多种,自行车,汽车,飞机,火车等,如果不使用任何模式,代码是酱婶儿的

public class TravelStrategy {  
    enum Strategy{  
        WALK,PLANE,SUBWAY  
    }  
    private Strategy strategy;  
    public TravelStrategy(Strategy strategy){  
        this.strategy=strategy;  
    }  

    public void travel(){  
        if(strategy==Strategy.WALK){  
            print("walk");  
        }else if(strategy==Strategy.PLANE){  
            print("plane");  
        }else if(strategy==Strategy.SUBWAY){  
            print("subway");  
        }  
    }  

    public void print(String str){  
        System.out.println("出行旅游的方式为:"+str);  
    }  

    public static void main(String[] args) {  
        TravelStrategy walk=new TravelStrategy(Strategy.WALK);  
        walk.travel();  

        TravelStrategy plane=new TravelStrategy(Strategy.PLANE);  
        plane.travel();  

        TravelStrategy subway=new TravelStrategy(Strategy.SUBWAY);  
        subway.travel();  
    }  
}  

很明显,如果需要增加出行方式就需要在增加新的else if语句,这违反了面向对象的原则之一,对修改封装(开放封闭原则)
题外话:面向对象的三大特征:封装,继承和多态

           五大基本原则:单一职责原则(接口隔离原则),开放封闭原则,Liskov替换原则,依赖倒置原则,良性依赖原则

好,回归主题,如何用策略模式来解决这个问题

首先,定义一个策略的接口

public interface Strategy {  
    void travel();  
}  

然后根据不同的出行方法来实现该接口

public class WalkStrategy implements Strategy{
      

    @Override  
    public void travel() {  
        System.out.println("walk");  
    }  

}  
public class PlaneStrategy implements Strategy{
      

    @Override  
    public void travel() {  
        System.out.println("plane");  
    }  

}  
public class SubwayStrategy implements Strategy{
      

    @Override  
    public void travel() {  
        System.out.println("subway");  
    }  

}  
public class TravelContext {  
    Strategy strategy;  

    public Strategy getStrategy() {  
        return strategy;  
    }  

    public void setStrategy(Strategy strategy) {  
        this.strategy = strategy;  
    }  

    public void travel() {  
        if (strategy != null) {  
            strategy.travel();  
        }  
    }  
}  

测试一下代码

public class Main {  
    public static void main(String[] args) {  
        TravelContext travelContext=new TravelContext();  
        travelContext.setStrategy(new PlaneStrategy());  
        travelContext.travel();  
        travelContext.setStrategy(new WalkStrategy());  
        travelContext.travel();  
        travelContext.setStrategy(new SubwayStrategy());  
        travelContext.travel();  
    }  
}  

以后如果再增加什么别的出行方式,就再继承策略接口即可,完全不需要修改现有的类
Android的源码中,策略模式也是使用相当广泛的,最典型的就是属性动画中的应用,我们知道,属性动画中有个叫插值器的东东,他的作用就是根据时间流逝的百分比来计算当前属性值改变的百分比

我们使用属性动画的时候,可以通过set方法对插值器进行设置,可以看到内部维持了一个时间差值器的引用,并设置getter和setter方法,默认情况下是先加速后减速的插值器,set方法如果传入的是null,则是线性插值器,而时间插值器TimeInterpolator是个接口,有一个接口继承了该接口,就是Interpolator,作用是为了保持兼容

private static final TimeInterpolator sDefaultInterpolator =  
        new AccelerateDecelerateInterpolator();    
private TimeInterpolator mInterpolator = sDefaultInterpolator;   
@Override  
public void setInterpolator(TimeInterpolator value) {  
    if (value != null) {  
        mInterpolator = value;  
    } else {  
        mInterpolator = new LinearInterpolator();  
    }  
}  

@Override  
public TimeInterpolator getInterpolator() {  
    return mInterpolator;  
}  
public interface Interpolator extends TimeInterpolator {
      
    // A new interface, TimeInterpolator, was introduced for the new android.animation  
    // package. This older Interpolator interface extends TimeInterpolator so that users of  
    // the new Animator-based animations can use either the old Interpolator implementations or  
    // new classes that implement TimeInterpolator directly.  
}  

此外,还有一个BaseInterpolateor 插值器实现了 Interpolator接口,是一个抽象类

abstract public class BaseInterpolator implements Interpolator {
      
    private int mChangingConfiguration;  
    /** 
     * @hide 
     */  
    public int getChangingConfiguration() {  
        return mChangingConfiguration;  
    }  

    /** 
     * @hide 
     */  
    void setChangingConfiguration(int changingConfiguration) {  
        mChangingConfiguration = changingConfiguration;  
    }  
}  

平时我们使用的时候通过设置不同的插值器,来实现不同的速率变化效果,比如线性,回弹,自由落体等,这些都是插值器接口的具体实现,也就是具体的插值器策略,详细看几个

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
      

    public LinearInterpolator() {  
    }  

    public LinearInterpolator(Context context, AttributeSet attrs) {  
    }  

    public float getInterpolation(float input) {  
        return input;  
    }  

    /** @hide */  
    @Override  
    public long createNativeInterpolator() {  
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();  
    }  
}  
public class AccelerateDecelerateInterpolator extends BaseInterpolator  
        implements NativeInterpolatorFactory {
      
    public AccelerateDecelerateInterpolator() {  
    }  

    @SuppressWarnings({
   "UnusedDeclaration"})  
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {  
    }  

    public float getInterpolation(float input) {  
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;  
    }  

    /** @hide */  
    @Override  
    public long createNativeInterpolator() {  
        return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();  
    }  
}  

内部使用的时候直接调用getInterpolation方法就可以返回对应值了,也就是属性值变化的百分比
属性动画中另外一个应用策略模式的地方就是估值器,他的作用是根据当前属性改变的百分比来计算改变后的属性值,该属性和插值器是类似的,有几个默认的实现,其中TypeEvaluator是一个接口。

public interface TypeEvaluator<T> {  

    public T evaluate(float fraction, T startValue, T endValue);  

}  
public class IntEvaluator implements TypeEvaluator<Integer> {
      

    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  
        int startInt = startValue;  
        return (int)(startInt + fraction * (endValue - startInt));  
    }  
}  
public class FloatEvaluator implements TypeEvaluator<Number> {
      

    public Float evaluate(float fraction, Number startValue, Number endValue) {  
        float startFloat = startValue.floatValue();  
        return startFloat + fraction * (endValue.floatValue() - startFloat);  
    }  
}  
public class PointFEvaluator implements TypeEvaluator<PointF> {  

    private PointF mPoint;  


    public PointFEvaluator() {  
    }  

    public PointFEvaluator(PointF reuse) {  
        mPoint = reuse;  
    }  

    @Override  
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {  
        float x = startValue.x + (fraction * (endValue.x - startValue.x));  
        float y = startValue.y + (fraction * (endValue.y - startValue.y));  

        if (mPoint != null) {  
            mPoint.set(x, y);  
            return mPoint;  
        } else {  
            return new PointF(x, y);  
        }  
    }  
}  

以上都是系统实现好的估值策略,在内部调用evaluate方法即可获得改变后的值,我们也可以自己定义自己的估值策略
在开源框架中,策略模式也无处不在,volley中,有一个策略重试接口

public interface RetryPolicy {  


    public int getCurrentTimeout();//获取当前请求用时(用于 Log)  


    public int getCurrentRetryCount();//获取已经重试的次数(用于 Log)  


    public void retry(VolleyError error) throws VolleyError;//确定是否重试,参数为这次异常的具体信息。在请求异常时此接口会被调用,可在此函数实现中抛出传入的异常表示停止重试。  
}  

在Volley中,该接口有一个默认的实现DefaultRetryPolicy,Volley默认的重试策略实现类,主要通过在retry(…)函数中判断 重试次数是否达到了上限,确定是否继续重试

public class DefaultRetryPolicy implements RetryPolicy {
      
    ...  
}  
public abstract class Request<T> implements Comparable<Request<T>> {
      
    private RetryPolicy mRetryPolicy;  
    public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {  
        mRetryPolicy = retryPolicy;  
        return this;  
    }  
    public RetryPolicy getRetryPolicy() {  
        return mRetryPolicy;  
    }  
}  

此外,各大网络请求框架,或多或少的会用到缓存,缓存一般会定义一个Cache接口,然后实现不同的缓存策略,如内存缓存,磁盘缓存,等等,这个缓存的实现,其实也是可以使用策略模式,直接看Volley,里边也有缓存

/** 
 * An interface for a cache keyed by a String with a byte array as data. 
 */  
public interface Cache {
      
    /** 
     * Retrieves an entry from the cache. 
     * @param key Cache key 
     * @return An {@link Entry} or null in the event of a cache miss 
     */  
    public Entry get(String key);  

    /** 
     * Adds or replaces an entry to the cache. 
     * @param key Cache key 
     * @param entry Data to store and metadata for cache coherency, TTL, etc. 
     */  
    public void put(String key, Entry entry);  

    /** 
     * Performs any potentially long-running actions needed to initialize the cache; 
     * will be called from a worker thread. 
     */  
    public void initialize();  

    /** 
     * Invalidates an entry in the cache. 
     * @param key Cache key 
     * @param fullExpire True to fully expire the entry, false to soft expire 
     */  
    public void invalidate(String key, boolean fullExpire);  

    /** 
     * Removes an entry from the cache. 
     * @param key Cache key 
     */  
    public void remove(String key);  

    /** 
     * Empties the cache. 
     */  
    public void clear();  

    /** 
     * Data and metadata for an entry returned by the cache. 
     */  
    public static class Entry {
      
        /** The data returned from cache. */  
        public byte[] data;  

        /** ETag for cache coherency. */  
        public String etag;  

        /** Date of this response as reported by the server. */  
        public long serverDate;  

        /** The last modified date for the requested object. */  
        public long lastModified;  

        /** TTL for this record. */  
        public long ttl;  

        /** Soft TTL for this record. */  
        public long softTtl;  

        /** Immutable response headers as received from server; must be non-null. */  
        public Map<String, String> responseHeaders = Collections.emptyMap();  

        /** True if the entry is expired. */  
        public boolean isExpired() {  
            return this.ttl < System.currentTimeMillis();  
        }  

        /** True if a refresh is needed from the original data source. */  
        public boolean refreshNeeded() {  
            return this.softTtl < System.currentTimeMillis();  
        }  
    }  

}  

他有两个实现类NoCache和DiskBsaedCache,使用的时候设置对应的缓存策略即可


5> 原型模式:

定义:

用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。

本宝宝看不懂,没代码说毛啊,上代码:

public class Person{  
    private String name;  
    private int age;  
    private double height;  
    private double weight;  

    public Person(){  

    }  

    public String getName() {  
        return name;  
    }  

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

    public int getAge() {  
        return age;  
    }  

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

    public double getHeight() {  
        return height;  
    }  

    public void setHeight(double height) {  
        this.height = height;  
    }  

    public double getWeight() {  
        return weight;  
    }  

    public void setWeight(double weight) {  
        this.weight = weight;  
    }  

    @Override  
    public String toString() {  
        return "Person{" +  
                "name='" + name + '\'' +  
                ", age=" + age +  
                ", height=" + height +  
                ", weight=" + weight +  
                '}';  
    }  
}  

要实现原型模式,按照以下步骤来:
1,实现一个Cloneable接口

public class Person implements Cloneable{
      

} 

重写Object的clone方法,在此方法中实现拷贝逻辑

@Override  
public Object clone(){  
    Person person=null;  
    try {  
        person=(Person)super.clone();  
        person.name=this.name;  
        person.weight=this.weight;  
        person.height=this.height;  
        person.age=this.age;  
    } catch (CloneNotSupportedException e) {  
        e.printStackTrace();  
    }  
    return person;  
}  

测试一下

public class Main {  
    public static void main(String [] args){  
        Person p=new Person();  
        p.setAge(18);  
        p.setName("张三");  
        p.setHeight(178);  
        p.setWeight(65);  
        System.out.println(p);  

        Person p1= (Person) p.clone();  
        System.out.println(p1);  

        p1.setName("李四");  
        System.out.println(p);  
        System.out.println(p1);  
    }  
}  

输出结果如下:

Person{name=’张三’, age=18, height=178.0, weight=65.0}
Person{name=’张三’, age=18, height=178.0, weight=65.0}
Person{name=’张三’, age=18, height=178.0, weight=65.0}
Person{name=’李四’, age=18, height=178.0, weight=65.0}

试想一下,两个不同的人,除了姓名不一样,其他三个属性都一样,用原型模式进行拷贝就会显得异常简单,这也是原型模式的应用场景之一

假设Person类还有一个属性叫兴趣集合,是一个List集合,就酱紫:

private ArrayList<String> hobbies=new ArrayList<String>();  

public ArrayList<String> getHobbies() {  
    return hobbies;  
}  

public void setHobbies(ArrayList<String> hobbies) {  
    this.hobbies = hobbies;  
}  

在进行拷贝的时候就要注意了,如果还是跟之前的一样操作,就会发现其实两个不同的人的兴趣集合的是指向同一个引用,我们对其中一个人的这个集合属性进行操作 ,另一个人的这个属性也会相应的变化,其实导致这个问题的本质原因是我们只进行了浅拷贝,也就是指拷贝了引用,最终两个对象指向的引用是同一个,一个发生变化,另一个也会发生拜变化。显然解决方法就是使用深拷贝

@Override  
public Object clone(){  
    Person person=null;  
    try {  
        person=(Person)super.clone();  
        person.name=this.name;  
        person.weight=this.weight;  
        person.height=this.height;  
        person.age=this.age;  

        person.hobbies=(ArrayList<String>)this.hobbies.clone();  
    } catch (CloneNotSupportedException e) {  
        e.printStackTrace();  
    }  
    return person;  
}  

不再是直接引用,而是拷贝了一份,

其实有的时候我们看到的原型模式更多的是另一种写法:在clone函数里调用构造函数,构造函数里传入的参数是该类对象,然后在函数中完成逻辑拷贝

@Override  
public Object clone(){  
    return new Person(this);  
}  
public Person(Person person){  
    this.name=person.name;  
    this.weight=person.weight;  
    this.height=person.height;  
    this.age=person.age;  
    this.hobbies= new ArrayList<String>(hobbies);  
}  

其实都差不多,只是写法不一样而已

现在 来看看Android中的原型模式:

先看Bundle类,

public Object clone() {  
    return new Bundle(this);  
}   
public Bundle(Bundle b) {  
    super(b);  

    mHasFds = b.mHasFds;  
    mFdsKnown = b.mFdsKnown;  
}  

然后是Intent类

@Override  
public Object clone() {  
    return new Intent(this);  
}  
public Intent(Intent o) {  
    this.mAction = o.mAction;  
    this.mData = o.mData;  
    this.mType = o.mType;  
    this.mPackage = o.mPackage;  
    this.mComponent = o.mComponent;  
    this.mFlags = o.mFlags;  
    this.mContentUserHint = o.mContentUserHint;  
    if (o.mCategories != null) {  
        this.mCategories = new ArraySet<String>(o.mCategories);  
    }  
    if (o.mExtras != null) {  
        this.mExtras = new Bundle(o.mExtras);  
    }  
    if (o.mSourceBounds != null) {  
        this.mSourceBounds = new Rect(o.mSourceBounds);  
    }  
    if (o.mSelector != null) {  
        this.mSelector = new Intent(o.mSelector);  
    }  
    if (o.mClipData != null) {  
        this.mClipData = new ClipData(o.mClipData);  
    }  
}  

用法也十分简单,一旦我们要用的Intent与现在的一个Intent很多东西都一样,那我们就可以直接拷贝现有的Intent,再修改不同的地方,便可以直接使用

Uri uri = Uri.parse("smsto:10086");      
Intent shareIntent = new Intent(Intent.ACTION_SENDTO, uri);      
shareIntent.putExtra("sms_body", "hello");      

Intent intent = (Intent)shareIntent.clone() ;  
startActivity(intent);  

网络请求中最常用的OkHttp中,也应用了原型模式,就在OkHttpClient类中,他实现了Cloneable接口

/** Returns a shallow copy of this OkHttpClient. */  
@Override   
public OkHttpClient clone() {  
    return new OkHttpClient(this);  
}  
private OkHttpClient(OkHttpClient okHttpClient) {  
    this.routeDatabase = okHttpClient.routeDatabase;  
    this.dispatcher = okHttpClient.dispatcher;  
    this.proxy = okHttpClient.proxy;  
    this.protocols = okHttpClient.protocols;  
    this.connectionSpecs = okHttpClient.connectionSpecs;  
    this.interceptors.addAll(okHttpClient.interceptors);  
    this.networkInterceptors.addAll(okHttpClient.networkInterceptors);  
    this.proxySelector = okHttpClient.proxySelector;  
    this.cookieHandler = okHttpClient.cookieHandler;  
    this.cache = okHttpClient.cache;  
    this.internalCache = cache != null ? cache.internalCache : okHttpClient.internalCache;  
    this.socketFactory = okHttpClient.socketFactory;  
    this.sslSocketFactory = okHttpClient.sslSocketFactory;  
    this.hostnameVerifier = okHttpClient.hostnameVerifier;  
    this.certificatePinner = okHttpClient.certificatePinner;  
    this.authenticator = okHttpClient.authenticator;  
    this.connectionPool = okHttpClient.connectionPool;  
    this.network = okHttpClient.network;  
    this.followSslRedirects = okHttpClient.followSslRedirects;  
    this.followRedirects = okHttpClient.followRedirects;  
    this.retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure;  
    this.connectTimeout = okHttpClient.connectTimeout;  
    this.readTimeout = okHttpClient.readTimeout;  
    this.writeTimeout = okHttpClient.writeTimeout;  
}  

该文章转载至人家的译文好像还是位妹子qaq

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/feng40492459/article/details/78144268

智能推荐

Visual Studio Code安装,基本操作,插件安装_visual studio插件安装-程序员宅基地

文章浏览阅读1.4k次,点赞2次,收藏3次。Visual Studio Code安装:这款软件给我印象就是(这款软件就是一个壳,功能很完善,强大到插件很完善)1.1:下载:官网网址:Download Visual Studio Code - Mac, Linux, WindowsVisual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows. Download Visual Studio Code to exper_visual studio插件安装

linux下增加swap的大小_linux 增加swap大小-程序员宅基地

文章浏览阅读1w次,点赞3次,收藏28次。使用dd命令来进行swap大小的扩容**1. 使用以下命令查看当前的swap大小是多少free -m输出的结果已兆(MB)为单位**2. 使用dd命令创建一个分区,如下命令:dd if=/dev/zero of=/home/swap bs=1024 count=1048576其中:if 表示input file,表示输入的文件,这里的输入文件为/dev/zero,也就是说扩......_linux 增加swap大小

window10下python2.7安装pip报错_win10 安装python2.7的pip出错-程序员宅基地

文章浏览阅读3.9k次。get-pip.py 文件内容来源于(将网页内容保存)https://bootstrap.pypa.io/get-pip.py报错信息D:\softs\python\Python27>python get-pip.pyDEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please ..._win10 安装python2.7的pip出错

python封装读取yaml文件的脚本_l.qaurl.vip-程序员宅基地

文章浏览阅读1.3k次。#一:封装读取yaml文件的脚本YAMLUtils.py# 1.在打开文件之前应先判断该文件是否存在,我们将判断写在类的初始化方法中class YAMLUtils: def __init__(self, filepath): # 判断添加 if os.path.exists(filepath): self.yamlfile =..._l.qaurl.vip

自用函数-程序员宅基地

文章浏览阅读128次。strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。[extern char *strstr(char *str1, const char *str2);memcpy指的是c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个_自用函数

MySQL插入数据时,如果记录不存在则insert,如果存在则update_mysql insert 语句 当存在则update-程序员宅基地

文章浏览阅读1.4w次,点赞4次,收藏15次。MySQL 当记录不存在时insert,当记录存在时更新网上基本有三种解决方法。第一种:示例一:insert多条记录假设有一个主键为 client_id 的 clients 表,可以使用下面的语句:INSERT INTO clients(client_id, client_name, client_type)SELECT supplier_id, supplier_na..._mysql insert 语句 当存在则update

随便推点

C# 使用反射原理构建接口后台简单架构_c# 反射 接口-程序员宅基地

文章浏览阅读721次,点赞3次,收藏5次。业务背景:在日常接口开发中,一个业务逻辑方法开发完成后,就需要对该方法公布一个接口供外界其他应用调用。这种方式在多人协作开发中,对公布的接口无法做到规范化管理,并且开发人员每次都需要定义新接口,再去写该接口的文档,会极大浪费开发人员的开发时间,无法做到开发人员只关注业务逻辑。那么由此延伸一个问题,是否有一种设计,仅公布一个接口,再根据一个请求的目的性,去自动调用指定的方法呢?对开发人员来说,就仅需要做一些标注,然后写文档只需要累加不同的请求目的的值、不同的参数即可,也大大简化了接口文档。基于以上问_c# 反射 接口

查看进程当前打开的文件数量_查看某个进程当前打开个数-程序员宅基地

文章浏览阅读1.5w次。1、针对ControlTier打开的页面有时会报一些奇怪错误2、其原因是由于CentOS系统默认打开的文件数量为10243、可以使用下面的方法①先找出这个进程的ID号,使用下面的命令ps -ef |grep jetty|awk '{print $2}'②然后根据这个进程ID号,统计出这个进程打开的文件数量lsof -p PID | wc -l4、可以使用下..._查看某个进程当前打开个数

基于python和OpenCV构建智能停车系统-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达当今时代最令人头疼的事情就是找不到停车位,尤其是找20分钟还没有找到停车位。根据复杂性和效率的不同,任何问题都具有一个..._python opencv+mysql停车场计费系统

类型多样的食品 食物免抠摄影素材,速来收藏_食品免扣图片-程序员宅基地

文章浏览阅读277次。最近看到很多朋友吐槽食品 食物免抠摄影素材不好找,有时花了大把时间却没找到合适的,而且有的时候会涉及到各种问题等,不仅工作效率降低,还闹心郁闷,所以今天就给大家分享一下小编自己在亲身体验和搜寻网站中,收集到的免费的食品 食物免抠摄影素材网站,希望能够帮助到大家。接下来就给大家介绍一下我珍藏已久的网站,我的工作灵感都是来源它哦,里面的食品 食物免抠摄影资源数量多,种类丰富,并且每隔一个月都会更新一次资源,可以说是非常宝藏了!为大家整理了免抠摄影-食品 食物免抠摄影合集为了方便大家更快的找到资源,小_食品免扣图片

2019 HDU 多校二_2019 multi-university training contest 2 题解-程序员宅基地

文章浏览阅读192次。1002Beauty Of Unimodal SequenceLIS+贪心:up[i][0] 表示以 i 结尾的最长严格上升序列的最长长度;up[i][1] 表示以 i 结尾的单峰最长的最长长度;down[i][0] 表示以 i 开头的最长严格下降序列的最长长度;down[i][1] 表示以 i 开头的单峰最长的最长长度;上面的四个数组我们可以用线段树很容易就可以维护出来,然..._2019 multi-university training contest 2 题解

java第三章选择结构教程_Java 第三章 选择结构1-程序员宅基地

文章浏览阅读94次。选择结构(一)会使用基本的 if 选择结构掌握逻辑运算符,掌握多重 if 选择结构 , 掌握嵌套 if 选择 结构为什么需要 if 选择结构例如: 如果张浩的 java 考试成绩大于 98分,张浩就能获得一个 MP4 作为奖励使用 if 选择结构 可以解决 。if 选择结构是根据条件判断之后 再做处理语法: 基本的 if 选择结构if (条件){//代码块 // 结果必须是boolean 类型..._使用if选择结构判断,如果笔试成绩大于98分且机试成绩大于80分,则奖励全班电影课一

推荐文章

热门文章

相关标签