android源码中使用到的设计模式(创建型)

1.单例模式

1.1定义

确保某个类只有一个实例,而且自行实例化并向整个系统提供者个实例。

1.2单例的形式

  • 饿汉模式:第一次就加载,用空间换时间。
public class SingleTon {
  private static SingleTon instance = new SingleTon();
  //构造函数不对外开放
  private SingleTon() {
  }
  //通过静态方法或枚举进行调用
  public static SingleTon getInstance() {
    return instance;
  }
}
  • 懒汉模式:只有在调用的时候才进行加载,但是第一次比较慢,用时间换空间,效率不高,并且线程不安全。
public class SingleTonLH {
  private static SingleTonLH instance;
  //构造函数不对外开放
  private SingleTonLH() {
  }

  //通过静态方法或枚举进行调用
  public static synchronized SingleTonLH getInstance() {
    if(instance == null){
      instance = new SingleTonLH();
    }
    return instance;
  }
}
  • 双重加锁模式:使用volatile和synchronized进行修饰。
public class SingleTonDCL {
  private static volatile SingleTonDCL instance;
 
  //构造函数不对外开放
  private SingleTonDCL() {
  }
  //通过静态方法或枚举进行调用
  public static SingleTonDCL getInstance() {
    if(instance == null){
      synchronized (SingleTonDCL.class) {
        if (instance == null){
          instance = new SingleTonDCL();
        }
      }
    }
    return instance;
  }
}
  • 静态内部类:线程安全,并且什么时候使用什么时候调用。
public class SingleTonFinal {
 
  // 构造函数不对外开放
  private SingleTonFinal() {
  }
 
  // 通过静态方法或枚举进行调用
  public static SingleTonFinal getInstance() {
    return SingleTonHolder.sinstance;
  }
 
  //反序列化
  private Object readResolve() throws ObjectStreamException {
    return SingleTonHolder.sinstance;
  }
  
  /**
   * 静态类部类
   */
  private static class SingleTonHolder {
    private static final SingleTonFinal sinstance = new SingleTonFinal();
  }
}
  • 枚举单例:
/**
 * 枚举单例
 */
public enum SingleTonEnum {
   INSTANCE;
   public void dosamething(){
     
   }
} 
/**
 * 调用方式
 */
class SingleTon {
  private SingleTon(){
    SingleTonEnum.INSTANCE.dosamething();
  }
}

  • 容器单例:
/**
 * 容器实现单例模式
 */
public class SingleTonManger {
  private static Map<String, Object> objMap = new HashMap<String, Object>();
 
  // 构造函数不对外开放
  private SingleTonManger() {
 
  }
 
  public static void registerService(String key, Object instance) {
    if (!objMap.containsKey(key)) {
      objMap.put(key, instance);
    }
  }
 
  public static Object getService(String key) {
    return objMap.get(key);
  }
}

1.3优缺点

优点:全局一个,节约资源。在读文件方面,可以防止同时操作。
缺点:不易扩展,如果要扩展需要修改代码,违背了开闭原则。

1.4 Android源码对应模式

我们经常在Activity中通过getSystemService(String name)这个函数来获取系统服务,比如WMS,AMS,LayoutIlater等,这些服务都会在某一个时刻以容器单例的形式保存在应用中。在源码中我们知道各个服务都是保存在ContextImpl类中,在其中定义了一个SystemServiceRegistry类

final class SystemServiceRegistry {
    // 存储所有系统服务的集合
    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =new HashMap<Class<?>, String>();
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
    
    // 一个注册服务的并添加到结合的方法
   private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }
    
    // 静态语句块, 只在类第一次被加载的时候调用, 保证了服务只被添加一次.
    static {
        // 注册了LayoutInflate服务
        registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});

                
       registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
                new CachedServiceFetcher<ActivityManager>() {
            @Override
            public ActivityManager createService(ContextImpl ctx) {
                return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
            }});
        /**
         *  后面省略一大坨的注册的服务代码
        **/
    }
    
    //获得服务
     public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
    
}

2.Buider模式

2.1定义

把一个复杂的类的构建过程和它的表示进行分离

构建模式

2.2说明

  • Director:统一组装过程
  • Product:产品抽象类
  • builder:抽象的builder类,规范产品的组建
  • concreteBuilder:具体的builder类

一般实现

1,Product 建立抽象类
/**
 * @describe 用户抽象类
 */
public abstract class Product {
  protected String name;
  protected String cardID;
  protected int age;
  protected String address;
 
  //定义抽象方法
  public abstract void setCardID();
 
  public void setName(String name) {
    this.name = name;
  }
 
  public void setAge(int age) {
    this.age = age;
  }
 
  public void setAddress(String address) {
    this.address = address;
  }
 
  //显示的内容让子类去实现
  protected abstract String showProductInfo();
}
2.具体产品类
 /** 
 * @describe product具体实现类
 */
public class SysProduct extends Product {
 
  @Override
  public void setCardID() {
    //设置默认ID
    cardID="10086"; 
  }
 
  @Override
  protected String showProductInfo() {
    return "User [name =" + name + ",cardID=" + cardID + ",age=" + age
        + "," + "address=" + address + "]";
  }
 
}
3.定义抽象的buider类
/**
 * @describe 抽象构造类
 */
abstract class Builder {
  Product product;
 
  public void buildName(String name) {
    product.setName(name);
  }
 
  public void buildCardID() {
    product.setCardID();
  }
 
  public void buildAge(int age) {
    product.setAge(age);
  }
 
  public void buildAddress(String address) {
    product.setAddress(address);
  }
 
  protected abstract void creat();
 
}
4.具体的buider实现类
/**
 * @describe 具体的builder类
 */
public class AccountBuilder extends Builder {
  SysProduct sysProduct;
 
  @Override
  protected void creat() {
    sysProduct = new SysProduct();
    sysProduct.setName("嘻嘻嘻");
    sysProduct.setAge(20);
    sysProduct.setCardID();
    sysProduct.setAddress("中国");
    System.out.println("Info : " + sysProduct.showProductInfo());
  }
 
}
5.统一组装类director
/**
 * @describe 统一组装类
 */
public class Director {
  Builder mBuilder = null;
 
  public Director(Builder builder) {
    this.mBuilder = builder;
    this.mBuilder.creat();
  }
}
6.调用
/**
 * @describe 测试类
 */
public class Test {
 
  public static void main(String[] args) {
     //统一组装
     new Director(new AccountBuilder());
  }
}

使用链式,简化Director

public class ChainProduct extends Product {
 
  @Override
  public void setCardID() {
    // 设置默认ID
    cardID = "10086";
  }
 
  @Override
  protected String showProductInfo() {
    return "Info : " + "User [name =" + name + ",cardID=" + cardID + ",age=" + age
        + "," + "address=" + address + "]";
  }
 
  public static class Builder {
    ChainProduct product;
 
    public Builder() {
      product = new ChainProduct();
    }
 
    public Builder buildName(String name) {
      product.setName(name);
      return this;
    }
 
    public Builder buildAge(int age) {
      product.setAge(age);
      return this;
    }
 
    public Builder buildAddress(String address) {
      product.setAddress(address);
      return this;
    }
    public Builder buildCardID() {
      product.setCardID();
      return this;
    }
    
    public void creat() {
      System.out.println(product.showProductInfo());
    }
  }
}
 
调用方式
new ChainProduct.Builder().buildAge(20).buildAddress("中国").creat();

2.3使用场景

  1. 相同的方法,不同的执行顺序,产生不同的事件结果
  2. 多个部件或者零件,都可以配装到一个对象,但是产生的运行结果不同
  3. 当初始化一个对象特别复杂,参数多,且很多参数默认的时候

2.4 优缺点

优点:封装性良好,使用可以使客户端不必知道产品内部组成细节。建造者独立易扩展。
缺点:会产生多余的builder对象和Director对象,消耗内存

2.5 android中使用

Director这个角色经常会被忽略. 而直接使用一个Builder来进行对象的封装, 并且这个Builder通常为链式调用, 它的每个setter方法都会返回this自身, 比如我们常用的AlertDialog。

// 一个粗略的创建dialog
// 创建构建者builder角色
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(android.R.drawable.sym_def_app_icon)
      .setTitle("标题")
      .setMessage("message")
      // 设置点击等..
      .setPositiveButton("确定", null);
// 构建
AlertDialog alertDialog = builder.create();
// 显示
alertDialog.show();

AlerDialog源代码:

public class AlertDialog extends Dialog implements DialogInterface {
    // AlertController 这个对象会保存Builder对象中的各个参数
    private AlertController mAlert;
    
    // 实际上操作的是上面这个变量中的属性
    @Override
    public void setTitle(CharSequence title) {
        super.setTitle(title);
        mAlert.setTitle(title);
    }
    
    public void setMessage(CharSequence message) {
        mAlert.setMessage(message);
    }
    // 省略一坨代码如各种setter等
    // Builder以内部类的形式存在
    public static class Builder {
        // 1.存储AlertDialog的各个参数 如title,icon等
        private final AlertController.AlertParams P;
        
        // 构造函数
        public Builder(Context context) {
            this(context, resolveDialogTheme(context, 0));
        }
        // 2. 设置参数, 我们构建的Builder设置的参数就是这些方法
        public Builder setTitle(int titleId) {
            P.mTitle = P.mContext.getText(titleId);
            return this;
        }
        
        public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }
        
        // ....
        
        // 3.构建AlertDialog, 传递参数
        public AlertDialog create() {
            // 4.因为已经通过builder设置了参数, 接下来就可以创建真正需要的AlertDialog对象
            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
            
            // 5.将Builder类中的成员变量P应用到AlertDialog类中
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }      
    }   
}

可以看到Android源码中的AlertDialog并没有遵循GOF设计模式中经典的实现方式, 而是进行了变种, 但却使其使用更加的方便. 这里AlertDialog.Builder这个类同时扮演了范例中的builder,具体实现builder,Director的角色. 简化了Builder设计模式, 因为模块比较稳定不会存在变化, 根据具体场景简化模式, 正是体现了灵活运用设计模式的实例.

3.原型模式

3.1定义

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

原型模式

3.2说明

Client:客户端用户
Prototype:抽象类或者接口,声明具备clone能力。
concretePrototype:具体实现原型。

3.3使用场景

  1. 类的初始化需要消耗很多资源
  2. 通过new产生一个对象需要非常繁琐的数据准备或者访问权限
  3. 一个对象需要提供给其他对象访问,而且其他各个调用者都需要修改其值,可以通过原型拷贝多个对象提供给调用者调用。

3.4涉及到的知识点

  • 赋值:对一个对象赋值一个对象,相当于两个对象对原来的对象都有控制权炒作一个另一个也有变化
//继承Cloneable类 相当于prototype接口。wordDocument相当于ConcreteProttype拥有赋值调用
public class WordDocument implements Cloneable {
 
  // 文字
  private String mText = "";
  // 图片
  private List<String> mImages = new ArrayList<String>();
 
  public String getText() {
    return mText;
  }
 
  public void setText(String mText) {
    this.mText = mText;
  }
 
  public List<String> getImages() {
    return mImages;
  }
 
  public void setImages(List<String> mImages) {
    this.mImages = mImages;
  }
  
  public void addImage(String img) {
    this.mImages.add(img);
  }
 
  /**
   * 打印文档内容
   */
  public void showDocument() {
    System.out.println("----------- Word Content Start -----------");
    System.out.println("Text : " + mText);
    System.out.println("Images List: ");
    for (String imgName : mImages) {
      System.out.println("image name : " + imgName);
    }
    System.out.println("----------- Word Content End -----------");
  }
}

赋值
  • 浅拷贝:重写clone()方法,但是没有对引用类型进行拷贝,造成一个对象的引用类型发生变化另一个也会变化
//在类中添加clone 进行浅拷贝
  @Override
  protected WordDocument clone() {
    try {
      WordDocument doc = (WordDocument) super.clone();
      doc.mText = this.mText;
      doc.mImages = this.mImages;
      return doc;
    } catch (Exception e) {
    }
    return null;
  }

浅拷贝
  • 深拷贝:对引用类型再次进行clone()
//进行深度拷贝
ArrayList重写了clone的方法
@SuppressWarnings("unchecked")
  @Override
  protected WordDocument clone() {
    try {
      WordDocument doc = (WordDocument) super.clone();
      doc.mText = this.mText;
      //对mImages调用clone进行深度拷贝
      doc.mImages =  ((List<String>) ((ArrayList<String>) this.mImages).clone());
      return doc;
    } catch (Exception e) {
    }
    return null;
  }

深拷贝

3.5 Android源码对应实现

  • ArrayList源码中的clone()
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
    transient Object[] elementData; 
    private int size;
    
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }
  • Intent中实现
    1.intent实现了Cloneable
public class Intent implements Parcelable, Cloneable {
}

2.对clone()重写


Intent

没有调用super.clone()使用了new Intent(this).当消耗不大的时候可以使用new

4.简单工厂模式

4.1定义

定义一个用于创建对象的接口,让子类决定实例化那个类

工厂方法模式

4.2使用场景

在任何需要创建复杂对象的地方,都可以使用工厂模式。但是能用new创建对象无需使用工厂方法模式。

4.3实现方式

一般实现流程

1.定义抽象产品类product
/** 
 * @describe 抽象产品类
 */
public abstract class Product {
 
  /**
   * 产品类的抽象方法,由具体的产品类去实现
   */
  public abstract void method();
}
2、具体的产品实现类
/** 
 * @describe 具体实现类A
 */
public class ConcreteProductA extends Product {
 
  @Override
  public void method() {
    System.out.println("我是具体的产品实现A");
  }
}
 
/** 
 * @describe 具体实现类B
 */
public class ConcreteProductB extends Product {
 
  @Override
  public void method() {
    System.out.println("我是具体的产品实现B");
  }
 
}
 
3.抽象工厂类 factory
/** 
 * @describe 抽象工厂类
 */
public abstract class Factory {
  
  /**
   * 抽象工厂类方法
   * @return 
   */
  public abstract Product CreateProuct();
}
4.具体实现工厂类
/**
 * @describe 抽象工厂类的具体实现方法
 */
public class ConcreteFactory extends Factory {
 
  @Override
  public Product CreateProuct() {
    return new ConcreteProductA();
  }
}
5.客户端调用
/**
 * @describe 调用类
 */
public class Client {
 
  public static void main(String[] args) {
    // 创建工厂
    Factory factory = new ConcreteFactory();
    // 创建产品
    Product product = factory.CreateProuct();
    // 调用产品的方法
    product.method();
  }
}

使用反射的方法进行工厂方法模式

1.创建反射工厂抽象类
/** 
 * @describe 使用反射的方便调用
 */
public abstract class Factory {
  public abstract <T extends Product> T createFactory(Class<T> clz);
}
2.具体的实现工厂类
/** 
 * @describe 具体的实现工厂类
 */
public class ConCreateFactory extends Factory{
 
  @SuppressWarnings("unchecked")
  @Override
  public <T extends Product> T createFactory(Class<T> clz) {
    Product p = null;
    try {
      p = (Product) Class.forName(clz.getName()).newInstance();
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
    return (T) p;
  }
3.调用方法
/**
 * @describe 调用类
 */
public class Client {
 
  public static void main(String[] args) {
    // 创建工厂
    Factory factory = new ConCreateFactory();
    // 创建产品
    Product product = factory.createFactory(ConcreteProductB.class);
    // 调用产品的方法
    product.method();
  }
}
}

4.3 android中的简单工厂方法模式

onCreate是一个工厂方法

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new FrameLayout(this));   
    }
}

通过onCrete这个方法,我们可以构建出任何样式的根布局。我们在不同的Activity#onCreate()方法将设置的布局通过setContentView()函数传递给frameworks并显示出来. 这不就是一个工厂模式的结构. 方法内部可以创建不同的对象, 产生不同的实例.

service中的onBind()也可以看成工厂方法模式

5.抽象工厂模式

5.1定义

为创建一组相关或者相互依赖的对象提供一个接口,而不需要指定它们的具体类

抽象工厂模式

5.2Android源码对应实现

抽象工厂在Android实现较少,基本上都可以用工厂方法模式解决。MediaPlayer底层使用的是抽象工厂模式

MediaPlayer
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容