zoukankan      html  css  js  c++  java
  • Android设计模式之单例模式

    公司组织技术沙龙,需要讲到关于设计模式的内容,在这里做一下笔录

    首先讲的是单例模式,

    单例模式: 一个类有且仅有一个实例,并且自行实例化向整个系统提供入口

    从定义上来看,其实看起来简单,但稍微会有点懵逼,我们待会从实际代码中去自行体会吧。。

    先来了解单例模式的一些特点:

    1.一个类只能有一个实例

    2.自己创建这个实例

    3.整个系统都使用这一个实例

    优势:

    1.能够避免实例重复创建

    2.能避免存在多个实例引起程序逻辑错误的场合

    3.节约内存

    我们先使用普通实例化的方式进行编程:

     1 package com.oysd.singleton;
     2 
     3 /**
     4  * @author ouyangshengduo
     5  * @description 不用单例模式运行的效果
     6  */
     7 
     8 //仓库类
     9 class StoreHouse {
    10     private int quantity = 100;
    11 
    12     public void setQuantity(int quantity) {
    13         this.quantity = quantity;
    14     }
    15 
    16     public int getQuantity() {
    17         return quantity;
    18     }
    19 }
    20 
    21 //搬货工人类
    22 class Carrier{
    23     public StoreHouse mStoreHouse;
    24     public Carrier(StoreHouse storeHouse){
    25         mStoreHouse = storeHouse;
    26     }
    27     //搬货进仓库
    28     public void MoveIn(int i){
    29         mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i);
    30     }
    31     //搬货出仓库
    32     public void MoveOut(int i){
    33         mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i);
    34     }
    35 }
    36 
    37 //工人搬运测试
    38 public class SinglePattern {
    39     public static void main(String[] args){
    40         StoreHouse mStoreHouse1 = new StoreHouse();
    41         StoreHouse mStoreHouse2 = new StoreHouse();
    42         Carrier Carrier1 = new Carrier(mStoreHouse1);
    43         Carrier Carrier2 = new Carrier(mStoreHouse2);
    44 
    45         System.out.println("两个是不是同一个?");
    46 
    47         if(mStoreHouse1.equals(mStoreHouse2)){//这里用equals而不是用 == 符号,因为 == 符号只是比较两个对象的地址
    48             System.out.println("是同一个");
    49         }else {
    50             System.out.println("不是同一个");
    51         }
    52         //搬运工搬完货物之后出来汇报仓库商品数量
    53         Carrier1.MoveIn(30);
    54         System.out.println("仓库商品余量:"+Carrier1.mStoreHouse.getQuantity());
    55         Carrier2.MoveOut(50);
    56         System.out.println("仓库商品余量:"+Carrier2.mStoreHouse.getQuantity());
    57     }
    58 }

    运行结果:

    1 两个是不是同一个?
    2 不是同一个
    3 仓库商品余量:130
    4 仓库商品余量:50

    以上出现了一些问题,两个实例不是同一个实例,造成了浪费,数据出现了矛盾,没有同步

    故而知单例存在的意义

    单例模式虽然简单,但功能还是比较强大的,他有好多种的编写方式,在此我暂时列举五种方式:

    第一种:只适用于单线程环境,一般用的比较少

     1 package com.oysd.singleton;
     2 /**
     3  * @author ouyangshengduo
     4  * @describe Singleton的静态属性instance中,只有instance为
     5  * null的时候才创建一个实例,构造函数私有,确保每次都只创建一个,避
     6  * 免重复创建。
     7  * 缺点:只在单线程的情况下正常运行,在多线程的情况下,就会出问题。
     8  * 例如:当两个线程同时运行到判断instance是否为空的if语句,并且
     9  * instance确实没有创建好时,那么两个线程都会创建一个实例。
    10  */
    11 public class Singleton {
    12     private static Singleton instance=null;
    13     private Singleton(){
    14         
    15     }
    16     public static Singleton getInstance(){
    17         if(instance==null){
    18             instance=new Singleton();
    19         }
    20         return instance;
    21     }
    22 }

    第二种:懒汉式,感觉不太好,因为整个方法都加上锁很耗资源

     1 package com.oysd.singleton;
     2 /**
     3  * @author ouyangshengduo
     4  * @descripbe 在解法一的基础上加上了同步锁,使得在多线程的情况下可
     5  * 以用。例如:当两个线程同时想创建实例,由于在一个时刻只有一个线程
     6  * 能得到同步锁,当第一个线程加上锁以后,第二个线程只能等待。第一个
     7  * 线程发现实例没有创建,创建之。第一个线程释放同步锁,第二个线程才
     8  * 可以加上同步锁,执行下面的代码。由于第一个线程已经创建了实例,所
     9  * 以第二个线程不需要创建实例。保证在多线程的环境下也只有一个实例。
    10  * 缺点:每次通过getInstance方法得到singleton实例的时候都有一个试
    11  * 图去获取同步锁的过程。而众所周知,加锁是很耗时的。能避免则避免。
    12  */
    13 public class Singleton {
    14     private static Singleton instance=null;
    15     private Singleton(){
    16         
    17     }
    18     public static synchronized Singleton getInstance(){
    19         if(instance==null){
    20             instance=new Singleton();
    21         }
    22         return instance;
    23     }
    24 }

    第三种:加同步锁,双重检查,建议使用

     1 package com.oysd.singleton;
     2 /**
     3  * @author ouyangshengduo
     4  * @description 只有当instance为null时,需要获取同步锁,创建一次实
     5  * 例。当实例被创建,则无需试图加锁。线程安全,效率高
     6  * 缺点:用双重if判断,复杂,容易出错
     7  */
     8 public class Singleton {
     9     private static Singleton instance=null;
    10     private Singleton(){
    11         
    12     }
    13     public static Singleton getInstance(){
    14         if(instance==null){
    15             synchronized(Singleton.class){
    16                 if(instance==null){
    17                     instance=new Singleton();
    18                 }
    19             }
    20         }
    21         return instance;
    22     }
    23 }

    第四种:饿汉式,线程安全,但耗内存,因为只要加载这个类,就会实例化对象

    package com.oysd.singleton;
    /**
     * @author ouyangshengduo
     * @description 初试化静态的instance创建一次。如果我们在Singleton类里
     * 面写一个静态的方法不需要创建实例,它仍然会早早的创建一次实例。而降
     * 低内存的使用率。
     *缺点:没有lazy loading的效果,从而降低内存的使用率
     */
    public class Singleton {
        private static Singleton instance=new Singleton();
        private Singleton(){
            
        }
        public static Singleton getInstance(){
            return instance;
        }
    }

    第五种:静态内部类

     1 package com.oysd.singleton;
     2 /**
     3  * @author ouyangshengduo
     4  * @description 定义一个私有的内部类,在第一次用这个嵌套类时,会创
     5  * 建一个实例。而类型为SingletonHolder的类,只有在
     6  * Singleton.getInstance()中调用,由于私有的属性,他人无法使用
     7  * SingleHolder,不调用Singleton.getInstance()就不会创建实例。
     8  * 优点:达到了lazy loading的效果,即按需创建实例
     9  */
    10 public class Singleton {
    11     private Singleton(){
    12         
    13     }
    14     private static class SingletonHolder{
    15         private final static Singleton instance=new Singleton();
    16     }
    17     public static Singleton getInstance(){
    18         return SingletonHolder.instance;
    19     }
    20 }

    然后通过单例模式来优化最开始出现的那个问题:

     1 package com.oysd.singleton;
     2 /**
     3  * @author ouyangshengduo
     4  * @description 单例模式运行效果
     5  */
     6 
     7 //单例仓库类
     8 class StoreHouse {
     9 
    10     //仓库商品数量
    11     private int quantity = 100;
    12     //自己在内部实例化
    13     private static StoreHouse ourInstance  = new StoreHouse();;
    14     //让外部通过调用getInstance()方法来返回唯一的实例。
    15     public static StoreHouse getInstance() {
    16         return ourInstance;
    17     }
    18 
    19     //封闭构造函数
    20     private StoreHouse() {
    21     }
    22 
    23     public void setQuantity(int quantity) {
    24         this.quantity = quantity;
    25     }
    26 
    27     public int getQuantity() {
    28         return quantity;
    29     }
    30 }
    31 
    32 
    33 //搬货工人类
    34 class Carrier{
    35     public StoreHouse mStoreHouse;
    36     public Carrier(StoreHouse storeHouse){
    37         mStoreHouse = storeHouse;
    38     }
    39     //搬货进仓库
    40     public void MoveIn(int i){
    41         mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i);
    42     }
    43     //搬货出仓库
    44     public void MoveOut(int i){
    45         mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i);
    46     }
    47 }
    48 
    49 //工人搬运测试
    50 public class SinglePattern {
    51     public static void main(String[] args){
    52         StoreHouse mStoreHouse1 = StoreHouse.getInstance();
    53         StoreHouse mStoreHouse2 = StoreHouse.getInstance();
    54         Carrier Carrier1 = new Carrier(mStoreHouse1);
    55         Carrier Carrier2 = new Carrier(mStoreHouse2);
    56 
    57         System.out.println("两个是不是同一个?");
    58 
    59         if(mStoreHouse1.equals(mStoreHouse2)){
    60             System.out.println("是同一个");
    61         }else {
    62             System.out.println("不是同一个");
    63         }
    64         //搬运工搬完货物之后出来汇报仓库商品数量
    65         Carrier1.MoveIn(30);
    66         System.out.println("仓库商品余量:"+Carrier1.mStoreHouse.getQuantity());
    67         Carrier2.MoveOut(50);
    68         System.out.println("仓库商品余量:"+Carrier2.mStoreHouse.getQuantity());
    69     }
    70 }

    运行结果:

    1 两个是不是同一个?
    2 是同一个
    3 仓库商品余量:130
    4 仓库商品余量:80
  • 相关阅读:
    java知识点-高级
    Java中高级面试题
    项目基础
    TFS Build Error: CSC : fatal error CS0042: Unexpected error creating debug information file 'xxxx.PDB'
    System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list
    (C#) System.BadImageFormatException: An attempt was made to load a program with an incorrect format.
    (C#) 引用工程中发现有黄色叹号
    (C#).NET 2.0 ~ 4.0 OS requirements.
    (WCF) WCF and Service Debug
    (WCF) WCF Service Hosting.
  • 原文地址:https://www.cnblogs.com/ouyangduoduo/p/6651883.html
Copyright © 2011-2022 走看看