zoukankan      html  css  js  c++  java
  • 设计模式5---创建型模式总结

    创建型模式共5种,单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。

    单例模式

    定义:确保某一个类的实例只有一个,而且向其他类提供这个实例。

    单例模式的使用场景:某个类的创建需要消耗大量资源,new一个对象代价太大,如访问IO和数据库等资源,或者避免多次创建该对象消耗内存过多。

    懒汉模式
    public class Singleton{
        private static Singleton instance;
    
        private Singleton(){}
    
        public static synchronized Singleton getInstance(){
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
        }
    
    }

    懒汉模式是当需要改单例对象时,才初始化,与之相对的是饿汉模式,静态变量instance声明时就初始化。

    由于每一次调用getInstance()都需要同步,资源消耗大。

    double check Lock
    public class Singleton{
        private static Singleton instance;
    
        private Singleton(){}
    
        public static Singleton getInstance(){
            if(instance == null){
                synchronize(Singleton.class){
                    if(instance == null){
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    在需要时才初始化,线程安全,且对象初始化后不再进行同步锁。

    第一次判断null为了不必要的同步,第二层判空是在没有其他线程进入同步块时,是否需要创建实例。但上述示例代码还是有问题,在代码instance = new Singleton()处, 代码会编译成多条指令,大致做了3件事:

    1.给Singleton的实例分配内存
    2.调用Singleton()构造函数,初始化成员字段
    3.强instance对象指向分配的内存空间(此时instance不为null)

    由于java编译器的指令执行在不影响结果的情况下是可以乱序的,所以无法保证上述2、3步骤是顺序执行的,这样当一个线程A获取单例时,先执行步骤3,步骤2还没有执行,就切换到线程B,由于此时instance已经不为空,所以线程B之间获得instance,但instance的初始化还没有完成,这样就会造成问题。

    解决DCL的失效问题就是在字段instance前面加入关键字volatile,该关键字禁止指令重排序优化,确保执行到instance = new Singleton()时的指令顺序按照上述步骤1-2-3执行。

    public class Singleton{
        private volatile static Singleton instance;
    
        private Singleton(){}
    
        public static Singleton getInstance(){
            if(instance == null){
                synchronize(Singleton.class){
                    if(instance == null){
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    静态内部类单例模式
    public class Singleton(){
        private Singleton(){}
    
        public static Singleton(){
            return InnerSingleton.instance;
        }
    
        //静态内部类
        private static class InnerSingleton{
            private static final Singleton instance = new Singleton();
        }
    }

    第一次加载Singleton时不会初始化instance,只有调用getInstance()时才初始化,因为此时需要加载静态内部类InnerSingleton。

    这种方式不仅确保线程安全,也能够保证单例对象的唯一性,同时也延迟了对象实例化。

    Android中的单例模式

    通过context获取的各种系统服务,和LayoutInflate都是采用单例模式

    WindowManager wm = (WindowManager) getSystemServie(getApplication().WINDOW_SERVICE);
    
    //ListView中getView中使用LayoutInflate
    itemView = LayoutInflate.from(context).inflate(id,null);

    Builder 创建者模式

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

    就是说某一个对象有许多字段参数需要设置,不同的设置得到不同的结果。

    public class Config{
        private int size;
        private int number;
        private String name;
    
        public Config(int size, int number, String name){
            this.size = size;
            this.number = number;
            this.name = name;
        }
    
        public void setSize(int size){
            this.size = size;
        }
    
        public void setNumber(int number){
            this.number = number;
        }
    
        public void setName(String name){
            this.name = name;
        }
    }

    如果只是极少数的变量需要设置,通过构造器还是可以接受的,如果变量个数特别多,构造器参数对应哪个变量就变得很难读懂,当只需要部分参数时,由需要重新写一个构造方法,这是很不利于程序扩展的。

    public class Config{
        private int size;
        private int number;
        private String name;
    
        public int getSize() {
            return size;
        }
    
        public int getNumber() {
            return number;
        }
    
        public String getName() {
            return name;
        }
    
        public static class Builder{
            private int size;
            private int number;
            private String name;
    
            public Builder setSize(int size){
                this.size = size;
                return this;
            }
    
            public Builder setNumber(int number){
                this.number = number;
                return this;
            }
    
            public Builder setName(String name){
                this.name = name;
                return this;
            }
    
            public Config build(){
                Config config = new Config();
                config.size = size;
                config.number = number;
                config.name = name;
                return config;
            }
        }
    }

    当我们需要初始化Config时,通过它的静态内部类Builder进行实例化

    Config.Builder builder = new Config.Builder();
    Config config = builder.setName("haha")
                    .setNumber(2)
                    .setSize(3)
                    .build();

    通过返回this实现链式调用,代码可读性强,也更好维护。

    Android中的Builder模式

    我们常用的提示框就采用了Builder模式

    AlertDialog.Builer builder=new AlertDialog.Builder(context);
    builder.setIcon(R.drawable.icon)
        .setTitle("title")
        .setMessage("message")
        .setPositiveButton("Button1", 
            new DialogInterface.OnclickListener(){
                public void onClick(DialogInterface dialog,int whichButton){
                    setTitle("click");
                }    
            })
        .create()
        .show();

    Notification从API11开始也采用了Builder模式

     Notification.Builder builder = new Notification.Builder(this);
            Intent intent = new Intent(this, MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    
            builder.setContentIntent(pendingIntent)
                    .setSmallIcon(R.drawable.ic_launcher)
                    .setWhen(System.currentTimeMillis())
                    .setContentText("内容")
                    .setContentTitle("标题")
                    .setTicker("状态栏上显示...")
                    .setNumber(2)
                    .setOngoing(true);
     //API11
      Notification notification = builder.getNotification();
    
      //API16
      Notification notification = builder.build();

    原型模式

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

    原型模式就是将一个对象进行克隆,将一个对象的内部属性完全复制,生成一个新的拷贝对象,被复制的实例对象就称为原型。当一个对象的属性过多时,重新new一个对象比较复杂和消耗资源,此时就可以用原型模式。

    public class CloneMode implements Cloneable {
    
        public String txt;
    
        public CloneMode(String txt) {
            this.txt = txt;
            System.out.println("----CloneMode构造函数----");
        }
    
        public CloneMode clone() {
            CloneMode cm;
            try {
                cm = (CloneMode) super.clone();
                cm.txt = this.txt;
                return cm;
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
    
        }
    
    }

    注意通过clone拷贝对象时并不会执行构造函数。还要注意的就是深拷贝浅拷贝,浅拷贝指的是拷贝原型对象时,并没有将原型对象的字段重新构造,而是将拷贝后的副本中的字段引用指向原型对象中的字段。举个例子:A引用B,这两个对象指向同一个地址,当修改A时,B也会改变,B修改时,A也会改变。深拷贝则对于原型对象中的引用类型字段也进行拷贝,生成一个新的引用对象。将上述代码添加一个引用类型对象,深拷贝如下:

    public class CloneMode implements Cloneable {
    
        public int num;
    
        //引用类型对象
        public ArrayList<String> lists = new ArrayList<>();
    
        public CloneMode(int num) {
            this.num = num;
            System.out.println("----CloneMode构造函数----");
        }
    
        public CloneMode clone() {
            CloneMode cm;
            try {
                cm = (CloneMode) super.clone();
                cm.num = this.num;
                //深拷贝:引用类型对象也进行拷贝;
                cm.lists = (ArrayList<String>)this.lists.clone();
    
                //浅拷贝
                //cm.lists = this.lists;
                return cm;
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
    
        }
    
    }

    Android中的原型模式

    Uri uri=Uri.parse("smsto:10086");
    Intent shareIntent=new Intent(Intent.ACTION_SENDTO,uri);
    
    //克隆副本
    Intent intent=(Intetn)shareIntent.clone();
    startActivity(intent);

    工厂模式

    定义:工厂模式定义一个用于创建对象的接口,让子类决定实例化哪个类。

    下述代码为工厂模式的通用代码

    public abstract class Product{
        public abstract void method();
    } 
    
    public class ConcreteProductA extends Prodect{
        public void method(){
            System.out.println("我是产品A!");
        }
    }
    
    public class ConcreteProductB extends Prodect{
        public void method(){
            System.out.println("我是产品B!");
        }
    }
    public  abstract class Factory{
        public abstract Product createProduct();
    }
    
    public class MyFactory extends Factory{
    
        public Product createProduct(){
            return new ConcreteProductA();
        }
    }

    Android中的工厂模式

    其实,在getSystemService方法中就是用到了工厂模式,他就是根据传入的参数决定创建哪个对象,当然了,由于返回的都是以单例模式存在的对象,因此不用new,直接把单例返回就好。

    public Object getSystemService(String name) {
        if (getBaseContext() == null) {
            throw new IllegalStateException("System services not available to Activities before onCreate()");
        }
        //........
        if (WINDOW_SERVICE.equals(name)) {
             return mWindowManager;
        } else if (SEARCH_SERVICE.equals(name)) {
            ensureSearchManager();
            return mSearchManager;
        }
        //.......
        return super.getSystemService(name);
      }

    抽象工厂模式

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

    模式通用代码:

    public abstract class AbstractProductA{
        public abstract void method();
    }
    public abstract class AbstractProdectB{
        public abstract void method();
    }
    
    public class ConcreteProductA1 extends AbstractProductA{
        public void method(){
            System.out.println("具体产品A1的方法!");
        }
    }
    public class ConcreteProductA2 extends AbstractProductA{
        public void method(){
            System.out.println("具体产品A2的方法!");
        }
    }
    public class ConcreteProductB1 extends AbstractProductB{
        public void method(){
            System.out.println("具体产品B1的方法!");
        }
    }
    public class ConcreteProductB2 extends AbstractProductB{
        public void method(){
            System.out.println("具体产品B2的方法!");
        }
    }
    
    public abstract class AbstractFactory{
        public abstract AbstractProductA createProductA();
    
        public abstract AbstractProductB createProductB();
    }
    
    public  class ConcreteFactory1 extends AbstractFactory{
        public  AbstractProductA createProductA(){
            return new ConcreteProductA1();
        }
    
        public  AbstractProductB createProductB(){
            return new ConcreteProductB1();
        }
    }
    
    public  class ConcreteFactory2 extends AbstractFactory{
        public  AbstractProductA createProductA(){
            return new ConcreteProductA2();
        }
    
        public  AbstractProductB createProductB(){
            return new ConcreteProductB2();
        }
    }

    Android中的抽象工厂模式

    从Framework角度来看,Activity和Service都可以看做是一个具体的工厂,oncreate()onBind()就相当于一个工厂方法。

  • 相关阅读:
    数据结构和算法(Golang实现)(9)基础知识-算法复杂度及渐进符号
    基于深度学习方法的dota2游戏数据分析与胜率预测(python3.6+keras框架实现)
    基于CBOW网络手动实现面向中文语料的word2vec
    《Machine Learning Yearing》读书笔记
    使用神经网络预测航班起飞准点率
    使用LSTM-RNN建立股票预测模型
    基于selenium+phantomJS的动态网站全站爬取
    TensorFlow保存、加载模型参数 | 原理描述及踩坑经验总结
    学习笔记--python中使用多进程、多线程加速文本预处理
    通过外汇对冲手段稳定获利的可行性验证
  • 原文地址:https://www.cnblogs.com/linghu-java/p/5692484.html
Copyright © 2011-2022 走看看