本章节讲述一些在Android开发中常见的设计模式。
1.单例模式
描述:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
优点:对于那些比较耗内存的类,只实例化一次可以大大提高性能,尤其是在移动开发中。保持程序运行的时候该中始终只有一个实例存在内存中。
举例:
懒汉式单例
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式单例
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
双重检测式单例
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
双重检测锁定(Double-Check Locking)方案属于懒汉式,使用延时加载技术,避免类加载时任务过重和造成资源浪费,同时将synchronized关键字加在代码块中,减少线程同步锁定以提升系统性能。instance实例使用了volatile关键字修饰,主要是避免在多线程环境下由于编译器进行的重排序操作而导致的线程安全问题。
volatile的作用是:作为指令关键字,确保本条指令不会因编译器的优化而省略。
详见:Android 线程Volatile关键字
单例模式在Android中的应用
1.1.Android-Universal-Image-Loader(图片加载框架)
public static ImageLoader imageLoader = ImageLoader.getInstance();//ImageLoader图片加载框架
public static ImageLoader getInstance() {
if (instance == null) {
Class var0 = ImageLoader.class;
synchronized(ImageLoader.class) {
if (instance == null) {
instance = new ImageLoader();
}
}
}
return instance;
}
1.2.EventBus(通讯框架)
EventBus.getDefault().register(this);
public static EventBus getDefault() {
if (defaultInstance == null) {
Class var0 = EventBus.class;
synchronized(EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
1.3.Volley(网络框架)
public class MySingleton {
private static MySingleton mInstance;
private RequestQueue mRequestQueue;
private static Context mCtx;
private MySingleton(Context context) {
mCtx = context;
mRequestQueue = getRequestQueue();
}
/**
* 获取对象静态方法
*/
public static synchronized MySingleton getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySingleton(context);
}
return mInstance;
}
/**
* 获取volley对象
*/
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());
}
return mRequestQueue;
}
}
2.Build模式
Build模式模式描述
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
举例
先有一个需要:创建一个Java Bean 属性包括:姓名,性别,年龄,身高,体重。然后创建几个相应的对象。
2.1.普通:
Java Bean
public class MyStudent {
private String name;
private String sex;
private String age;
private String height;
private String weight;
public MyStudent(String name,String sex,String age,String height,String weight){
this.name=name;
this.sex=sex;
this.age=age;
this.height=height;
this.weight=weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
}
调用
MyStudent myStudent=new MyStudent("张三","男","25","175","180");
String result="姓名:"+myStudent.getName()+" 性别:"+myStudent.getSex()+" 年龄:"+myStudent.getAge()+" 身高:"+myStudent.getHeight()+" 体重:"+myStudent.getWeight();
Log.d("TAG","result----:"+result);
结果
result----:姓名:张三 性别:男 年龄:25 身高:175 体重:180
由此可见,结果是没有任何问题的。可是如果构造方法的参数再增加几个,在用构造方法传递参数时就可能不知道那个数值对应那个参数了。这时用Builder模式就会明了一点。
2.2.Build模式
Java Bean
public class MyStudent {
private String name;
private String sex;
private String age;
private String height;
private String weight;
public MyStudent(Builder builder){
this.name=builder.name;
this.sex=builder.sex;
this.age=builder.age;
this.height=builder.height;
this.weight=builder.weight;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public String getAge() {
return age;
}
public String getHeight() {
return height;
}
public String getWeight() {
return weight;
}
public static class Builder{
private String name;
private String sex;
private String age;
private String height;
private String weight;
public Builder name(String name){
this.name=name;
return this;
}
public Builder sex(String sex){
this.sex=sex;
return this;
}
public Builder age(String age){
this.age=age;
return this;
}
public Builder height(String height){
this.height=height;
return this;
}
public Builder weight(String weight){
this.weight=weight;
return this;
}
public MyStudent build() {
return new MyStudent(this);
}
}
}
调用
MyStudent.Builder builder=new MyStudent.Builder();
MyStudent myStudent=builder.name("小丽")
.sex("女")
.age("24")
.height("165")
.weight("90")
.build();
String result="姓名:"+myStudent.getName()+" 性别:"+myStudent.getSex()+" 年龄:"+myStudent.getAge()+" 身高:"+myStudent.getHeight()+" 体重:"+myStudent.getWeight();
Log.d("TAG","result----:"+result);
结果
result----:姓名:小丽 性别:女 年龄:24 身高:165 体重:90
由此可知在赋值时就比构造方法传递参数清晰的多了。
Builder模式在Android中的应用
2.1.对话框
AlertDialog.Builder builder=new AlertDialog.Builder(this);
AlertDialog alertDialog=builder.setTitle("对话框")
.setMessage("这是一个对话框")
.setIcon(R.mipmap.iv3)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.create();
alertDialog.show();
2.2.Android-Universal-Image-Loader DisplayImageOptions 获取
ImageLoaderConfiguration configuration=ImageLoaderConfiguration.createDefault(this);
CliniciansApplication.imageLoader.init(configuration);
options = new DisplayImageOptions.Builder()
.showImageForEmptyUri(R.mipmap.doctor_ava)
.showImageOnFail(R.mipmap.doctor_ava)
.cacheInMemory(true).cacheOnDisc(true)
.bitmapConfig(Bitmap.Config.RGB_565).build();
2.3.网络请求框架OkHttp
mOkHttpClient=new OkHttpClient.Builder()
.connectTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//连接时间
.readTimeout(DataConstant.nettimeout,TimeUnit.SECONDS)//读时间
.writeTimeout(DataConstant.nettimeout,TimeUnit.SECONDS)//写时间
.build();
3.观察者模式
观察者模式描述
观察者模式有三个典型的方法,注册,反注册(取消注册),发送。它定义对象间的一种一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都能得到通知并被自动更新。观察上面两个情景,有一个共同点,就是我们无需每时每刻关注我们感兴趣的东西,我们只需做的就是订阅感兴趣的事物,比如天气预报服务,杂志等,一旦我们订阅的事物发生变化,比如有新的天气预报信息,新的杂志等,被订阅的事物就会即时通知到订阅者,即我们。而这些被订阅的事物可以拥有多个订阅者,也就是一对多的关系。当然,严格意义上讲,这个一对多可以包含一对一,因为一对一是一对多的特例,没有特殊说明,本文的一对多包含了一对一。
观察者模式的几个重要组成
3.1.观察者,我们称它为Observer,有时候我们也称它为订阅者,即Subscriber。
3.2.被观察者,我们称它为Observable,即可以被观察的东西,有时候还会称之为主题,即Subject。
观察者模式Android中的应用
3.1.广播(四大组件之一,在此不做太多的赘述)
3.2.EventBus(以Activity中使用为例)
onCreate方法中 注册
EventBus.getDefault().register(this);
onDestroy方法中 反注册
EventBus.getDefault().unregister(this);
接收
public void onEventMainThread(EventBusBean eventBusBean) {
if(null!=eventBusBean){
if(list.size()>0&&updateposition>=0&&updateposition
某个Action下发送(一般在另一Activity中发送)
EventBusBean eventBusBean=new EventBusBean();
eventBusBean.setContext(msgText);
EventBus.getDefault().post(eventBusBean);
4.原型模式
描述:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
实现原型模式,步骤如下
4.1.实现Cloneable接口。
4.2.重写Object的clone方法。
4.3.实现clone方法中的拷贝逻辑。
代码举例
Java Bean
public class Student implements Cloneable {
private String name;
private String sex;
private String age;
public Student(){
}
public Student(String name,String sex,String age){
this.name=name;
this.sex=sex;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public Object clone() {
Student student=null;
try {
student= (Student) super.clone();
student.name=this.name;
student.sex=this.sex;
student.age=this.age;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
public String toString(){
return "姓名:"+name+" 性别:"+sex+" 年龄:"+age;
}
}
调用
Student student=new Student();
student.setAge("28");
student.setName("张三");
student.setSex("男");
Student clonestudent1=null;
Student clonestudent2=null;
clonestudent1= (Student) student.clone();
clonestudent2= (Student) student.clone();
clonestudent2.setName("张三1");
String result1="原有对象\n姓名:"+student.getName()+"\n性别:"+student.getSex()+"\n年龄:"+student.getAge();
Log.d("TAG","result1----:"+result1);
Log.d("TAG","------------------------------------------------------------------------------");
String result2="克隆对象1\n姓名:"+clonestudent1.getName()+"\n性别:"+clonestudent1.getSex()+"\n年龄:"+clonestudent1.getAge();
Log.d("TAG","result2----:"+result2);
String result3="克隆对象2\n姓名:"+clonestudent2.getName()+"\n性别:"+clonestudent2.getSex()+"\n年龄:"+clonestudent2.getAge();
Log.d("TAG","result3----:"+result3);
clonestudent1原样拷贝 clonestudent2原样拷贝后修改了姓名
结果
result1----:原有对象
姓名:张三
性别:男
年龄:28
result2----:克隆对象1
姓名:张三
性别:男
年龄:28
result3----:克隆对象2
姓名:张三1
性别:男
年龄:28
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
如果Java Bean中有一集合
Java Bean
public class Student implements Cloneable {
private String name;
private String sex;
private String age;
private List list;
public Student(){
}
public Student(String name,String sex,String age,List list){
this.name=name;
this.sex=sex;
this.age=age;
this.list=list;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
@Override
public Object clone() {
Student student=null;
try {
student= (Student) super.clone();
student.name=this.name;
student.sex=this.sex;
student.age=this.age;
student.list=this.list;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return student;
}
public String toString(){
return "姓名:"+name+" 性别:"+sex+" 年龄:"+age;
}
}
调用
Student student=new Student();
student.setAge("28");
student.setName("张三");
student.setSex("男");
List list=new ArrayList<>();
list.add("詹姆斯,韦德,保罗,安东尼");
student.setList(list);
Student clonestudent1= (Student) student.clone();
List lists=new ArrayList<>();
lists.add("詹姆斯,韦德");
clonestudent1.setList(lists);
List list1=student.getList();
int len1=list1.size();
StringBuilder stringBuilder=new StringBuilder();
for(int i=0;i list2=clonestudent1.getList();
int len2=list2.size();
StringBuilder stringBuilder2=new StringBuilder();
for(int i=0;i
结果
result1----:原有对象
姓名:张三
喜爱的球星:詹姆斯,韦德,保罗,安东尼,
result2----:克隆对象
姓名:张三
喜爱的球星:詹姆斯,韦德,
和普通属性没有区别
注:Java克隆详解:Java Cloneable接口使用
5.策略模式
描述:策略模式定义了一些列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变换。
问题描述:假设我们要出去旅游,而去旅游出行的方式有很多,有步行,有坐火车,有坐飞机等等。
代码举例
普通:
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语句,而这违反了面向对象的原则之一,对修改封闭。而这时候,策略模式则可以完美的解决这一切。
策略接口
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();
}
}
如果加一个自行车 添加一个类即可
public class BikeStrategy implements Strategy{
@Override
public void travel() {
System.out.println("bike");
}
}