android开发中,必要的了解一些设计模式又是非常有必要的。 Android开发的设计模式,基本设计思想源于java的设计模式
java的设计模式有N多种,据不完全统计,迄今为止,网络出现最频繁的大概有23种。
设计模式的出现就是为了高质量、易维护和复用性强的代码
设计模式分为三种类型:
保证一个类仅有一个实例,全局只有一个访问点。
对单例的实现可以分为两大类——懒汉式和饿汉式,他们的区别在于:
懒汉式:指全局的单例实例在第一次被使用时构建
饿汉式:指全局的单例实例在类装载时构建。
从它们的区别也能看出来,日常我们使用的较多的应该是懒汉式的单例,毕竟按需加载才能做到资源的最大化利用
摘录自这一篇聊一聊Java的单例
实现方法详解看七种方式实现Singleton模式
/**
* 单例模式,使用静态内部类,线程安全(推荐)
*/
public static class Singleton5 {
private final static class SingletonHolder {
private static final Singleton5 INSTANCE = new Singleton5();
}
public static Singleton5 getInstance() {
return SingletonHolder.INSTANCE;
}
}
它利用了ClassLoader来保证了同步,同时又能让开发者控制类加载的时机。从内部看是一个饿汉式的单例,但是从外部看来,又的确是懒汉式的实现。
/**
* 静态内部类,使用枚举方式,线程安全(推荐)
*/
public enum Singleton6 {
INSTANCE;
public void whateverMethod() {
}
}
这是极简的写法,利用了创建枚举实例的过程是线程安全的。所以这种写法也没有同步的问题。但是enum比较耗资源,需要权衡。
/**
* 静态内部类,使用双重校验锁,线程安全(推荐)
*/
public static class Singleton {
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
这是一种双检锁实例的方式,只在第一次实例化的时候进行加锁,并在在加锁前后都会对是否实例化了进行判定.
性能方面优于单检锁的形式.为了避免编译器对new Singleton()进行优化,instance变量加上volatile修饰,去除编译器优化的干扰.
Android中的系统级服务都是通过容器的单例模式实现方式,以单例形式存在,减少了资源消耗。
定义一个用于创建对象的接口,让子类决定将哪一个类实例化。
麦当劳的点餐,可以点可乐,汉堡这可以使用Builder模式,也可以点套餐,这个可以认为是工厂模式
public class FactoryDemo {
public static void start() {
Order order = OrderFactory.createBigMacCombo();
System.out.println(order.makeOrder());
}
}
------------------------Factory
public class OrderFactory {
//创建一份巨无霸套餐
public static Order createBigMacCombo() {
return new Order.OrderBuilder()
.addBurger(new BigMac())
.addBeverage(new Coke())
.build();
}
}
--------------------------Order
public class Order {
private IBurgers mBurger;
private IBeverages mBeverages;
private Order(OrderBuilder builder){
mBurger = builder. mBurger;
mBeverages = builder. mBeverages;
}
public String makeOrder(){
StringBuilder sb = new StringBuilder();
if ( mBurger!= null) {
sb.append( mBurger.makeBurger()).append( " ");
}
if ( mBeverages!= null) {
sb.append( mBeverages.makeDrinking()).append( " ");
}
return sb.toString();
}
public static class OrderBuilder{
private IBurgers mBurger;
private IBeverages mBeverages;
public OrderBuilder(){
}
public OrderBuilder addBurger(IBurgers burgers){
this. mBurger = burgers;
return this;
}
public OrderBuilder addBeverage(IBeverages beverages){
this. mBeverages = beverages;
return this;
}
public Order build(){
return new Order( this);
}
}
}
---------------------------------Product
public class BigMac implements IBurgers {
@Override
public String makeBurger() {
return "巨无霸";
}
}
public class Coke implements IBeverages {
@Override
public String makeDrinking() {
return "可乐";
}
}
public interface IBeverages {
String makeDrinking();
}
public interface IBurgers {
String makeBurger();
}
Android中,BitmapFactory用于从不同的数据源来解析、创建Bitmap对象
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。
使用场景:一个对象族或者一组没有任何关系的对象都有相同的约束,都可以使用抽象工厂模式
角色介绍:
但是抽象工厂模式有个最大的缺点:产品族扩展非常困难,严重违反了开闭原则
用户只需要告诉Factory要的产品,不需要关心产品是如何生产的。不过每增加一样产品,BaseAppFactory都要增加一个方法,然后所有的实现类都要修改
public class FactoryDemo {
public static void start() {
BaseAppFactory factory = new MacAppFactory();
BaseTextEditor textEditor = factory.createTextEditor();
textEditor.edit();
textEditor.save();
BaseImageEditor imageEditor = factory.createImageEditor();
imageEditor.edit();
imageEditor.save();
}
}
--------------------Factory
public class MacAppFactory extends BaseAppFactory {
@Override
public BaseTextEditor createTextEditor() {
return new MacTextEditor();
}
@Override
public BaseImageEditor createImageEditor() {
return new MacImageEditor();
}
}
public abstract class BaseAppFactory {
public abstract BaseTextEditor createTextEditor();
public abstract BaseImageEditor createImageEditor();
}
-----------------Products
public class MacImageEditor extends BaseEditor {
@Override
public void edit() {
System.out.println("图片处理编辑器,edit -- Mac版");
}
@Override
public void save() {
System.out.println("图片处理编辑器,save -- Mac版");
}
}
public class MacTextEditor extends BaseEditor {
@Override
public void edit() {
System.out.println("文本编辑器,edit -- Mac版");
}
@Override
public void save() {
System.out.println("文本编辑器,edit -- Mac版");
}
}
public abstract class BaseEditor {
public abstract void edit();
public abstract void save();
}
Android底层对MediaPlayer的创建。
MediaPlayerFactory是Android底层为了创建不同的MediaPlayer所定义的一个类。
用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。基本可以理解成实现了clone方法
使用场景:在系统中要创建大量的对象,这些对象之间具有几乎完全相同的功能,只是在细节上有一点儿差别
的几种不同格式:ARGB_8888、RGB_565、ARGB_4444、ALAPHA_8等。
那我们就可以先创建一个ARGB_8888的Bitmap作为原型,在它的基础上,通过调用Bitmap.copy(Config)来创建出其它几种格式的Bitmap。
另外一个例子就是Java中所有对象都有的一个名字叫clone的方法,已经原型模式的代名词了。
核心Code
注意像ListView这类的需要深度copy
public class Person implements Cloneable {
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;
}
private ArrayList hobbies = new ArrayList();
public ArrayList getHobbies() {
return hobbies;
}
public void setHobbies(ArrayList hobbies) {
this.hobbies = hobbies;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
", weight=" + weight +
'}';
}
@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) this.hobbies.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return person;
}
}
Android中的Bundle类,该类实现了Cloneable接口
public Object clone() {
return new Bundle(this);
}
public Bundle(Bundle b) {
super(b);
mHasFds = b.mHasFds;
mFdsKnown = b.mFdsKnown;
}
Intent类,该类也实现了Cloneable接口
@Override
public Object clone() {
return new Intent(this);
}
public Intent(Intent o) {
this.mAction = o.mAction;
this.mData = o.mData;
this.mType = o.mType;
......
}
使用的时候可以直接拷贝现有的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接口
@Override
public OkHttpClient clone() {
return new OkHttpClient(this);
}
private OkHttpClient(OkHttpClient okHttpClient) {
this.routeDatabase = okHttpClient.routeDatabase;
this.dispatcher = okHttpClient.dispatcher;
this.proxy = okHttpClient.proxy;
......
}
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
———–优化前
当有很多参数时,编写这个构造函数就会显得异常麻烦
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);
public class Person {
private String name;
private int age;
private double height;
private double 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;
}
public Person(String name, int age, double height, double weight) {
this.name = name;
this.age = age;
this.height = height;
this.weight = 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;
}
}
———–优化后
如果换一个角度,试试Builder模式,可读性可是嗖嗖的~
我们给Person增加一个静态内部类Builder类,并修改Person类的构造函数。
创建过程一下子就变得非常清晰了。对应的值是什么属性一目了然,可读性大大增强。
Person.Builder builder=new Person.Builder();
Person person=builder
.name("张三")
.age(18)
.height(178.5)
.weight(67.4)
.build();
public class PersonNew {
private String name;
private int age;
private double height;
private double weight;
private PersonNew(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;
}
public 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 PersonNew build() {
return new PersonNew(this);
}
}
}
在Android中, Builder模式也是被大量的运用。
比如常见的对话框的创建AlertDialog.Builder,ImageLoader的初始配置。
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中有两个常见的类也是Builder模式:StringBuilder和StringBuffer
还有比较著名框架中:Gson中的GsonBuilder
GsonBuilder builder=new GsonBuilder();
Gson gson=builder.setPrettyPrinting()
.disableHtmlEscaping()
.generateNonExecutableJson()
.serializeNulls()
.create();
EventBus中也有一个Builder
EventBus(EventBusBuilder builder) {...}
OkHttp中的
Request.Builder builder=new Request.Builder();
Request request=builder.addHeader("","")
.url("")
.post(body)
.build();
private Response(Builder builder) {...}
各大框架中大量的运用了Builder模式。
小结:
Github Code: https://github.com/vivianking6855/android-advanced/tree/master/DesignPattern
Android开发中常见的设计模式
Android设计模式之23种设计模式一览
《Android深入透析》之常用设计模式经验谈
《android之大话设计模式》
设计模式中英文对照
Android 设计模式