设计模式之单例模式

学习这个的原因原因是在做java框架的时候回顾底层源码的时候发现一些程序的设计模式,思来想去学校好像没教,所以就先学几个常用的。以下的内容都是手打的花费时间是一周,总的来说学习了设计模式的原则和几个简单的设计模式,但是主要是单例设计模式有代码 其他的由于需要写很多的类所以就不贴出来了(单例模式还是比较熟练的(我指的是多并发的情况下我也能说清楚为啥这样使用比如双重锁结构))

设计模式之单例模式

黄伟晟的设计模式课堂笔记

设计模式的目的

代码重用性:相同代码,不多次编写

可读性:即是规范性

可扩展性:可维护性

可靠性:当增加功能后,对原有代码无影响

高内聚,低耦合

设计模式需要遵守的7大原则

单一职责原则 singleresponsibility

对类来说,一个类只负责一项功能。

接口隔离原则 segregation

客户端不应该依赖它不需要的接口,即是一个类对另一个类的依赖应该建立在最小的接口上

拆分接口~~~

依赖倒转原则 inversion

1.高层模块不应该依赖低层模块,二者都应该依赖其抽象

2.抽象不应该依赖细节,细节应该依赖抽象

3.依赖倒转的中心思想是面向接口编程

4.使用接口或者抽象类的目的是制定好规范,不涉及任何具体的操作,把展现的细节交给他们的实现类来完成

注意事项

低层模块尽量都要有抽象类或者接口,或者两者都有,这样的程序稳定性更好,

变量的声明类型精力是抽象类或接口,这样我们的变量引用和实际对象间。纯在一个缓冲层,有利于程序的扩展和优化

继承准寻里式替换原则

里氏替换原则 loskov

子类尽量不要重写父类的方法

适当情况下通过聚合,组合,依赖来解决问题

开闭原则 ocp

1.一个软件实体如类,模块和函数应该对扩展开放,对修改关闭,用抽象构建框架,用实现扩展细节

2.当软件需要变化的时候,尽量通过扩展软件的实体的行为来实现变化,而不是通过修改已有的代码来实现变化

迪米特法则 demeter

一个对象应该对其他对象保持最少的了解

类与类关系越密切,耦合度越大

即是一个类对自己依赖的类知道的越少越好1.即是对于被依赖的类不管多复杂,都尽量将逻辑封装在类的内部,对外提供public方法不对外泄露信息。

合成复用原则 composite

尽量使用合成/聚合的方式,而不是聚合

UML




## 单例模式 Singleton

new  有三个指令 1. 分配对象的内存空间 2. 初始化对象 3. 设置instance指向的内存空间

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

### 饿汉式(静态常量)

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

2.类的内部创建对象

3.向外暴露一个静态的公有方法。getInstance

4.代码实现

```java

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;

}

}

```

优缺点说明

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

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

这种方式基于classload机制避免了多线程的同步问题,不过,instance在类装载的时候就实例化,在单例模式中大多数都是调用getInstance方法,但是导致类装载的原因有很多,因此不能确定有没有其他的方式导致类装载,就不能起到懒加载的效果。

结论:这种单例模式可用,就是可能造成内存浪费。

### 饿汉式(静态变量)

```java

public class SingletonTest02 {

  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  static Singleton instance;

  static { // 在静态代码块中,创建单例对象

      instance = new Singleton();

  }

  //3. 提供一个公有的静态方法,返回实例对象

  public static Singleton getInstance() {

      return instance;

  }

}

```

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

```java

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. 起到了懒加载的效果,但是只能在单线程下使用

2. 如果是多线程下,一个线程进入了if(singleton == null)判断语句块,还没来得及往下执行又有一个线程访问这个语句,就会创建多个实例,所以这个在多线程环境下不适用

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

### 懒汉式(线程安全)

```java

public class SingletonTest04 {

public static void main(String[] args) {

System.out.println("懒汉式2 , 线程安全~");

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() {}

//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题

//即懒汉式

public static synchronized Singleton getInstance() {

if(instance == null) {

          //  synchronized(Singleton.class)

instance = new Singleton();//(这里加同步代码块没有用,解决不了线程安全问题)

}

return instance;

}

}

```

优缺点说明:

1. 解决了线程不安全的问题

2. 效率太低了,每一个线程在获得实现类实例的时候,执行getInstance()方法都要进行同步,而其实这个方法值执行一次实例化代码就够了,后面的想获得该类实例直接return即可

3. 结论:实际开发中,不推荐使用这种方法

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

```java

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;

//如果不使用volatile关键字,可能出现异常,因为instance = new SingleTo();不是一个原子操作

    //即是保证一个线程更新了instance其他的线程立刻得知,即是一个线程更新立刻刷到内存中 防止初始化独享和分配内存地址直接的重排序

private Singleton() {}

//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题

//同时保证了效率, 推荐使用

public static synchronized Singleton getInstance() {

if(instance == null) {

synchronized (Singleton.class) {

if(instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

}

```

优缺点说明

1. Double-check概念是多线程开发中常使用到的,如代码中所示,我们进行了两次if(singleton == null)检查,这样可以保证线程安全了

2. 这样,实例化代码只用执行一次,后面再次访问的时候,判断if(singleton == null),直接return实例化对象,也避免反复进行方法的同步。

3. 线程安全,延迟加载,效率较高

4. 结论:在实际的开发中,推荐使用这样的单例设计模式

### 静态内部类完成单例模式

```JAVA

package com.atguigu.singleton.type7;

public class SingletonTest07 {

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() {}

//写一个静态内部类,该类中有一个静态属性 Singleton

private static class SingletonInstance {

private static final Singleton INSTANCE = new Singleton();

}

//提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE

public static synchronized Singleton getInstance() {

return SingletonInstance.INSTANCE;

}

}

```

优缺点说明

1. 这种方式采用了类装载的机制来保证初始化实例的时候只有一个线程

2. 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化的时候调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化

3. 类的静态属性保证只会才第一次加载类的时候初始化,所以在此,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的

4. 优点,避免了线程不安全,利用静态内部类她点实现延迟加载,效率高

5. 结论:推荐使用

### 枚举实现单例

```java

public class SingletonTest08 {

public static void main(String[] args) {

Singleton instance = Singleton.INSTANCE;

Singleton instance2 = Singleton.INSTANCE;

System.out.println(instance == instance2);

System.out.println(instance.hashCode());

System.out.println(instance2.hashCode());

instance.sayOK();

}

}

//使用枚举,可以实现单例, 推荐

enum Singleton {

INSTANCE; //属性

public void sayOK() {

System.out.println("ok~");

}

}

```

诶,博客园不支持md语法~

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

推荐阅读更多精彩内容