单例模式与工厂方法模式

来源:互联网 发布:qq飞车b车 大黄蜂数据 编辑:程序博客网 时间:2024/05/16 12:01
    单例模式
http://blog.csdn.net/happy_horse/article/details/51164262
http://blog.csdn.net/beyond0525/article/details/22794221/
http://blog.csdn.net/liguangzhenghi/article/details/8076361
单例模式保证了在程序中只有一个实例存在并且能全局的访问到。(1.应用中某个实例对象需要频繁的被访问.2.应用中只允许存在一个实例)
实现单例模式有以下几个关键点:
(1)其构造函数不对外开放,一般为private;(构造函数私有化,使得客户端不能通过new的形式手动构造单例类的对象。)
(2)通过一个静态方法或者枚举返回单例类对象;(单例类的实例一旦创建,便不会被系统回收,除非手动设置为null。)
(3)确保单例类的对象有且只有一个,尤其要注意多线程的场景;
(4)确保单例类对象在反序列化时不会重新创建对象;
一、懒汉式(线程不安全)
    //懒汉式单例类.在第一次调用的时候实例化自己   
    public class Singleton {
        //私有的构造函数
        private Singleton() {}
        //私有的静态变量
        private static Singleton single=null;
        //暴露的公有静态方法   
        public static Singleton getInstance() {
            if (single == null) {
                single = new Singleton();
            }
            return single;
        }
    }
(2)懒汉式(线程安全)使用synchronized 关键字
public class Singleton {  
    //私有的静态变量
    private static Singleton instance;  
    //私有的构造方法
    private Singleton (){};
    //公有的同步静态方法
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}  
每次调用getInstance()都进行同步,造成了不必要的同步开销。这种模式一般不建议使用。在Android源码中使用的该单例方法有:InputMethodManager,AccessibilityManager等都是使用这种单例模式
(3)饿汉模式(线程安全)
//饿汉式单例类.在类初始化时,已经自行实例化   
public class Singleton {  
    //static修饰的静态变量在内存中一旦创建,便永久存在
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}
(4)DCL双重校验模式
public class Singleton {  
    private volatile static Singleton singleton;  //静态变量
    private Singleton (){}  //私有构造函数
    public static Singleton getInstance() {  
      if (singleton == null) {  //第一层校验
          synchronized (Singleton.class) {  
          if (singleton == null) {  //第二层校验
              singleton = new Singleton();  
          }  
        }  
      }  
    return singleton;  
    }  
}  
对singleton 进行了两次判断是否空,第一层判断是为了避免不必要的同步,第二层的判断是为了在null的情况下才创建实例。存在严重安全隐患。
(5)静态内部类单例模式
public class Singleton {  
    private Singleton (){} ;//私有的构造函数
    public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
    }  
    //定义的静态内部类
    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  //创建实例的地方
    }  
}
当第一次加载Singleton 类的时候并不会初始化INSTANCE ,只有第一次调用Singleton 的getInstance()方法时才会导致INSTANCE 被初始化。因此,第一次调用getInstance()方法会导致虚拟机加载SingletonHolder 类,这种方式不仅能够确保单例对象的唯一性,同时也延迟了单例的实例化。
使用:SingletonInner.getInstance();  
(6)枚举单例
public enum Singleton {  //enum枚举类
    INSTANCE;  
    public void whateverMethod() {  

    }  
}
(7)使用容器实现单例模式
public class SingletonManager {
  private static Map<String, Object> objMap = new HashMap<String,Object>();//使用HashMap作为缓存容器
  private Singleton() {
  }
  public static void registerService(String key, Objectinstance) {
    if (!objMap.containsKey(key) ) {
      objMap.put(key, instance) ;//第一次是存入Map
    }
  }
  public static ObjectgetService(String key) {
    return objMap.get(key) ;//返回与key相对应的对象
  }
}
在程序的初始,将多种单例模式注入到一个统一的管理类中,在使用时根据key获取对应类型的对象。
在Android源码中,APP启动的时候,虚拟机第一次加载该类时会注册各种ServiceFetcher,比如LayoutInflater Service。将这些服务以键值对的形式存储在一个HashMap中,用户使用时只需要根据key来获取到对应的ServiceFetcher,然后通过ServiceFetcher对象的getService函数获取具体的服务对象。当第一次获取时,会调用ServiceFetcher的creatService函数创建服务对象,然后将该对象缓存到一个列表中,下次再取时直接从缓存中获取,避免重复创建对象,从而达到单例的效果。Android中的系统核心服务以单例形式存在,减少了资源消耗。
总结:不管以哪种形式实现单例模式,它们的核心原理是将构造函数私有化,并且通过静态公有方法获取一个唯一的实例,在这个获取的过程中必须保证线程的安全,同时也要防止反序列化导致重新生成实例对象。

   工厂方法模式

http://blog.csdn.net/self_study/article/details/51419770

         任何需要生成复杂对象的地方,都可以使用工厂方法模式。工厂方法模式(Factory Method Pattern)定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类,这样的设计将对象的创建封装其来,以便于得到更松耦合,更有弹性的设计。降低了对象之间的耦合度,代码结构清晰,对调用者隐藏了产品的生产过程,生产过程改变后,调用者不用做什么改变,易于修改。易于拓展,要增加工厂和产品都非常方便,直接实现接口,不用修改之前的代码。

    Product(抽象产品角色):它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
    ConcreteProduct(具体产品角色):具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
    Factory(抽象工厂角色):这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
    ConcreteFactory(具体工厂角色):它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

模式1
1.抽象的产品:
public abstract class Product {
    public abstract void method();
}
2.具体的产品:
public class ConcreteProductA extends Product {
    @Override
    public void method() {
        System.out.println("产品A");
    }
}
public class ConcreteProductB extends Product {
    @Override
    public void method() {
        System.out.println("产品B");
    }
}
3.抽象的工厂:
public abstract class Factory {
    public abstract Product createProduct();
}
4.具体的工厂:
public class ConcreteFactory extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}
5.客户端使用:
public class Client {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactory();
        Product product = factory.createProduct();
        product.method();
    }
}
这样就生产出来一个ConcreteProductA。

模式2
通过反射来了解要生产哪个产品
1.抽象工厂:
public abstract class Factory {
    public abstract <T extends Product> T createProduct(Class<T> clz);
}
2.具体工厂:
public class ConcreteFactory extends Factory {
    @Override
    public <T extends Product> T createProduct(Class<T> clz) {
        Product  product = null;
        try {
            product= (Product) Class.forName(clz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}
3.客户端调用:
public class Client {
    public static void main(String[] args) {
        Factory factory = new ConcreteFactory();
        Product product = factory.createProduct(ConcreteProductB.class);
        product.method();
    }
}
这样,客户端调用的时候,传入什么产品就生产什么产品。

模式3
可以为每个产品都创建一个具体的工厂类,如:
public class ConcreteFactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}
public class ConcreteFactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}
要生产哪个就调用哪个工厂。这种叫多工厂方法模式。