20

Java内功心法之设计模式学习(二)

 3 years ago
source link: https://segmentfault.com/a/1190000038176639
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在上一篇文章简单的讲解了设计模式的七大原则和UML类图的使用,这篇文章开始学习23种设计模式。

一、设计模式类型

设计模式分为三种类型,共 23 种

1) 创建型模式 :单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。

2) 结构型模式 :适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

3) 行为型模式 :模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)。

注意:不同的书籍上对分类和名称略有差别。

二、单例设计模式

1.1 单例设计模式介绍

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法(静态方法)。

比如 Hibernate 的 SessionFactory,它充当数据存储源的代理,并负责创建 Session 对象。SessionFactory 并不是轻量级的,一般情况下,一个项目通常只需要一个 SessionFactory 就够,这是就会使用到单例模式。

1.2 单例设计模式八种方式

单例模式有八种方式:

1) 饿汉式(静态常量)
2) 饿汉式(静态代码块)

3) 懒汉式(线程不安全)

4) 懒汉式(线程安全,同步方法)

5) 懒汉式(线程安全,同步代码块)

6) 双重检查
7) 静态内部类

8) 枚举

1.2.1 饿汉式(静态常量)

饿汉式(静态常量)应用实例

步骤如下:

1) 构造器私有化 (防止 new )

2) 类的内部创建对象

3) 向外暴露一个静态的公共方法。getInstance

4) 代码实现

package com.atguigu.singleton.type1;

public class SingletonTest01 {

  public static void main(String[] args) {
    //测试
    Singleton instance = Singleton.getInstance();
    Singleton instance2 = Singleton.getInstance();    
    System.out.println(instance == instance2); // true
    System.out.println("instance.hashCode=" +  instance.hashCode()); 
    System.out.println("instance2.hashCode=" +  instance2.hashCode());
  }

}


//饿汉式(静态变量) 
class Singleton {
  //1. 构造器私有化,  外部能 new 
  private Singleton() {}

  //2.本类内部创建对象实例
  private final static Singleton instance = new Singleton();

  //3. 提供一个公有的静态方法,返回实例对象
  public static Singleton getInstance() { 
    return instance;
  }
}

➢ 优缺点说明:

1) 优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。

2) 缺点:在类装载的时候就完成实例化,没有达到 Lazy Loading 的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费

3) 这种方式基于 classloder 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,在单例模式中大多数都是调用 getInstance 方法, 但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 就没有达到 lazy loading 的效果

4) 结论:这种单例模式可用,可能造成内存浪费

1.2.2 懒汉式(线程不安全)

package com.atguigu.singleton.type3;


public class SingletonTest03 {
 
  public static void main(String[] args) {
    System.out.println("懒汉式 1 , 线程不安全~");
    Singleton instance = Singleton.getInstance(); 
    Singleton instance2 = Singleton.getInstance(); 
    System.out.println(instance == instance2); // true
  
    System.out.println("instance.hashCode=" +  instance.hashCode());   
     System.out.println("instance2.hashCode=" + instance2.hashCode());
  }
}


class Singleton {
  private static Singleton instance;
  private Singleton() {}

  // 提供一个静态的公有方法,当使用到该方法时,才去创建 instance
  // 即懒汉式
  public static Singleton getInstance() { 
  if(instance == null) {
    instance = new Singleton();
  }
  return instance;
 }
}

➢ 优缺点说明:

1) 起到了 Lazy Loading 的效果,但是只能在单线程下使用。

2) 如果在多线程下,一个线程进入了 if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式

3) 结论:在实际开发中,不要使用这种方式

1.2.3 双重检查

package com.atguigu.singleton.type6;


public class SingletonTest06 {

  public static void main(String[] args) {
    System.out.println("双重检查");
    Singleton instance = Singleton.getInstance(); 
    Singleton instance2 = Singleton.getInstance(); 
    System.out.println(instance == instance2); // true
    System.out.println("instance.hashCode=" + instance.hashCode());
    
    System.out.println("instance2.hashCode=" + instance2.hashCode());
 
}

}

// 懒汉式(线程安全,同步方法) 
class Singleton {
  private static volatile Singleton instance;
  private Singleton() {}

 //提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
//同时保证了效率, 推荐使用


public static synchronized Singleton getInstance() {  

   if(instance == null) {
      synchronized (Singleton.class) { 
      if(instance == null) {
         instance = new Singleton();
      }
   }
  }
   return instance;
 }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK