Android中所涉及的常用设计模式.docx
《Android中所涉及的常用设计模式.docx》由会员分享,可在线阅读,更多相关《Android中所涉及的常用设计模式.docx(29页珍藏版)》请在冰豆网上搜索。
Android中所涉及的常用设计模式
Android中所涉及的常用设计模式
1、单例模式
概念:
Ensureaclasshasonlyoneinstance,andprovideaglobalpointofaccesstoit.
动态确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
优点:
1.1、由于单例模式在内存中只有一个实例,减少了内存开销。
对于那些耗内存的类,只实例化一次,大大提高性能,尤其是移动开发中。
1.2、单例模式可以避免对资源的多重占用,例如一个写文件时,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
1.3、单例模式可以在系统设置全局的访问点,优化和共享资源访问。
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassSingleton{
privatevolatilestaticSingletoninstance=null;
privateSingleton(){
}
publicstaticSingletongetInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance=newSingleton();
}
}
}
returninstance;
}
}
构造函数私有化,定义静态函数获得实例就不多说了,这里着重说一下volatile:
volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从内存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.(首先我们要先意识到有这样的现象,编译器为了加快程序运行的速度,对一些变量的写操作会先在寄存器或者是CPU缓存上进行,最后才写入内存.
而在这个过程,变量的新值对其他线程是不可见的.而volatile的作用就是使它修饰的变量的读写操作都必须在内存中进行!
)
synchronized
同步块大家都比较熟悉,通过synchronized关键字来实现,所有加上synchronized和块语句,在多线程访问的时候,同一时刻只能有一个线程能够用
synchronized修饰的方法或者代码块。
volatile
用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。
volatile很容易被误用,用来进行原子性操作。
再就是这个双重判断null:
这是因为如果线程A进入了该代码,线程B在等待,这是A线程创建完一个实例出来后,线程B获得锁进入同步代码,实例已经存在,木有必要再创建一个,所以双重判断有必要。
Android中用到的地方很多,比如Android-Universal-Image-Loader中的单例,EventBus中的单例
最后给出一个管理我们activity的类,可以作为一个简单工具类
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassActivityManager{
privatestaticvolatileActivityManagerinstance;
privateStackmActivityStack=newStack();
privateActivityManager(){
}
publicstaticActivityManagergetInstance(){
if(instance==null){
synchronized(ActivityManager.class){
if(instance==null){
instance=newActivityManager();
}
}
returninstance;
}
publicvoidaddActicity(Activityact){
mActivityStack.push(act);
}
publicvoidremoveActivity(Activityact){
mActivityStack.remove(act);
}
publicvoidkillMyProcess(){
intnCount=mActivityStack.size();
for(inti=nCount-1;i>=0;i--){
Activityactivity=mActivityStack.get(i);
activity.finish();
}
mActivityStack.clear();
android.os.Process.killProcess(android.os.Process.myPid());
}
}
单例模式在Android源码中的应用:
在Android源码中,使用到单例模式的例子很多,如:
InputMethodManager类
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
publicfinalclassInputMethodManager{
staticfinalbooleanDEBUG=false;
staticfinalStringTAG="InputMethodManager";
staticfinalObjectmInstanceSync=newObject();
staticInputMethodManagermInstance;
finalIInputMethodManagermService;
finalLoopermMainLooper;
创建唯一的实例staticInputMethodManagermInstance;
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
/**
*RetrievetheglobalInputMethodManagerinstance,creatingitifit
*doesn'talreadyexist.
*@hide
*/
staticpublicInputMethodManagergetInstance(Contextcontext){
returngetInstance(context.getMainLooper());
}
/**
*Internally,theinputmethodmanagercan'tbecontext-dependent,so
*wehavethisherefortheplacesthatneedit.
*@hide
*/
staticpublicInputMethodManagergetInstance(LoopermainLooper){
synchronized(mInstanceSync){
if(mInstance!
=null){
returnmInstance;
}
IBinderb=ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManagerservice=IInputMethodManager.Stub.asInterface(b);
mInstance=newInputMethodManager(service,mainLooper);
}
returnmInstance;
}
防止多线程同时创建实例:
synchronized(mInstanceSync){
if(mInstance!
=null){
returnmInstance;
}
当没有创建实例对象时,调用mInstance=newInputMethodManager(service,mainLooper);
其中类构造函数如下所示:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
InputMethodManager(IInputMethodManagerservice,Looperlooper){
mService=service;
mMainLooper=looper;
mH=newH(looper);
mIInputContext=newControlledInputConnectionWrapper(looper,
mDummyInputConnection);
if(mInstance==null){
mInstance=this;
}
}
2、建造者模式(Builder模式)
定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
概念就是比较抽象的,让大家很难理解的,如果简单从这个一个概念就搞懂了这个模式的话,那就不用费力的去查资料整理后边的东西了。
这里我们通过一个例子来引出Build模式。
假设有一个Person类,他的一些属性可以为null,可以通过这个类来构架一大批人
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassPerson{
privateStringname;
privateintage;
privatedoubleheight;
privatedoubleweight;
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicintgetAge(){
returnage;
}
publicvoidsetAge(intage){
this.age=age;
}
publicdoublegetHeight(){
returnheight;
}
publicvoidsetHeight(doubleheight){
this.height=height;
}
publicdoublegetWeight(){
returnweight;
}
publicvoidsetWeight(doubleweight){
this.weight=weight;
}
}
然后为了方便,你可能会写这么一个构造函数来传属性
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicPerson(Stringname,intage,doubleheight,doubleweight){
this.name=name;
this.age=age;
this.height=height;
this.weight=weight;
}
或者为了更方便还会写一个空的构造函数
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicPerson(){
}
有时候还会比较懒,只传入某些参数,又会来写这些构造函数
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
publicPerson(Stringname){
this.name=name;
}
publicPerson(Stringname,intage){
this.name=name;
this.age=age;
}
publicPerson(Stringname,intage,doubleheight){
this.name=name;
this.age=age;
this.height=height;
}
于是就可以来创建各种需要的类
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
Personp1=newPerson();
Personp2=newPerson("张三");
Personp3=newPerson("李四",18);
Personp4=newPerson("王二",21,180);
Personp5=newPerson("麻子",16,170,65.4);
其实这种写法的坏处在你写的过程中想摔键盘的时候就该想到了,既然就是一个创建对象的过程,怎么这么繁琐,并且构造函数参数过多,其他人创建对象的时候怎么知道各个参数代表什么意思呢,这个时候我们为了代码的可读性,就可以用一下Builder模式了
给Person类添加一个静态Builder类,然后修改Person的构造函数,如下:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassPerson{
privateStringname;
privateintage;
privatedoubleheight;
privatedoubleweight;
privatePerson(Builderbuilder){
this.name=builder.name;
this.age=builder.age;
this.height=builder.height;
this.weight=builder.weight;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicintgetAge(){
returnage;
}
publicvoidsetAge(intage){
this.age=age;
}
publicdoublegetHeight(){
returnheight;
}
publicvoidsetHeight(doubleheight){
this.height=height;
}
publicdoublegetWeight(){
returnweight;
}
publicvoidsetWeight(doubleweight){
this.weight=weight;
}
staticclassBuilder{
privateStringname;
privateintage;
privatedoubleheight;
privatedoubleweight;
publicBuildername(Stringname){
this.name=name;
returnthis;
}
publicBuilderage(intage){
this.age=age;
returnthis;
}
publicBuilderheight(doubleheight){
this.height=height;
returnthis;
}
publicBuilderweight(doubleweight){
this.weight=weight;
returnthis;
}
publicPersonbuild(){
returnnewPerson(this);
}
}
}
从上边代码我们可以看到我们在Builder类中定义了一份跟Person类一样的属性,通过一系列的成员函数进行赋值,但是返回的都是this,最后提供了一个build函数来创建person对象,对应的在Person的构造函数中,传入了Builder对象,然后依次对自己的成员变量进行赋值。
此外,Builder的成员函数返回的都是this的另一个作用就是让他支持链式调用,使代码可读性大大增强
于是我们就可以这样创建Person对象
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
Person.Builderbuilder=newPerson.Builder();
Personperson=builder
.name("张三")
.age(18)
.height(178.5)
.weight(67.4)
.build();
是不是有那么点感觉了呢
Android中大量地方运用到了Builder模式,比如常见的对话框创建
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
AlertDialog.Builderbuilder=newAlertDialog.Builder(this);
AlertDialogdialog=builder.setTitle("对话框")
.setIcon(android.R.drawable.ic_dialog)
.setView(R.layout.custom_view)
.setPositiveButton(R.string.positive,newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
}
})
.setNegativeButton(R.string.negative,newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
}
})
.create();
dialog.show();
其实在java中StringBuilder和StringBuffer都用到了Builder模式,只不过是稍微简单一点了
Gson中的GsonBuilder
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
GsonBuilderbuilder=newGsonBuilder();
Gsongson=builder.setPrettyPrinting()
.disableHtmlEscaping()
.generateNonExecutableJson()
.serializeNulls()
.create();
网络框架OKHttp
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
Request.Builderbuilder=newRequest.Builder();
Requestrequest=builder.addHeader("","")
.url("")
.post(body)
.build();
可见大量框架运用了Builder设计模式,总结一下吧:
定义一个静态内部类Builder,内部成员变量跟外部一样
Builder通过一系列方法给成员变量赋值,并返回当前对象(this)
Builder类内部提供一个build方法方法或者create方法用于创建对应的外部类,该方法内部调用了外部类的一个私有化构造方法,该构造方法的参数就是内部类Builder
外部类提供一个私有化的构造方法供内部类调用,在该构造函数中完成成员变量的赋值
3、观察者模式
定义:
Defineaone-to-manydependencybetweenobjectssothatwhenoneobjectchangesstate,allitsdependentsaernotifiedandupdatedautomatically.
定义对象间一种一对多的依赖关系,使得当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
主要包括四个部分:
1.Subject被观察者。
是一个接口或者是抽象类,定义被观察者必须实现的职责,它必须能偶动态地增加、取消观察者,管理观察者并通知观察者。
2.Observer观察者。
观察者接收到消息后,即进行update更新操作,对接收到的信息进行处理。
3.ConcreteSubject具体的被观察者。
定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。
4.ConcreteObserver具体观察者。
每个观察者在接收到信息后处理的方式不同,各个观察者有自己的处理逻辑。
这个好像还好理解那么一点点,不过还是先来讲个情景,
天气预报的短信服务,一旦付费订阅,每次天气更新都会向你及时发送
其实就是我们无需每时每刻关注我们感兴趣的东西,我们只需要订阅它即可,一旦我们订阅的事务有变化了,被订阅的事务就会即时的通知我们
我们来看一下观察者模式的组成:
观察者,我们称它为Observer,有时候我们也称它为订阅者,即Subscriber
被观察者,我们称它为Observable,即可以被观察的东西,有时候还会称之为主题,即Subject
至于观察者模式的具体实现,java里为我们提供了Observable类和Observer接口供我们快速实现该模式,但是这里为了加深印象,不用这个两个类
我们来模拟上边的场景,先定义一个Weather的类
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassWeather{
privateString