[知识点] 漫谈设计模式 03

第二篇 创建对象

- 直接使用new 所带来的高耦合度。

- 如何避免耦合度?

- OOP带给我们的好处之一是封装,如果封装这些实例化的细节,即对客户对象隐藏实例化的过程,

 那么我们新添加一个接口的实现或者抽象类的具体类,也不会影响客户代码了,降低了耦合度。

- 客户对象(Client)和服务对象(Service) -->可移植性和重用性

-- Chapter 3: 单例模式【Singleton】

-> 如何保证一个类在一个系统里面只有一个实例?

-- Chapter 4: 工厂方法模式【Factory method】

-> 如何实例化对象使得对象和使用者之间的耦合度降低?

-- Chapter 5: 原型模式【Prototype】

-> 如何拷贝现有的对象快速的创建一个新的复杂对象?

-- Chapter 6: 控制反转【IoC】

-> IoC和依赖注入DI  Inverse of contrale

# 3.1 概述

- 一个系统里只有一个类

- 常见:缓存池,数据库连接池,线程池,一些应用服务实例等

- 在多线程的环境中,为了保证实例的唯一性实则不易

# 3.2 最简单的实例

- 该类的构造方法是私有的(外部类无法创建)

- 提供一个全局访问点

- [code]

public class Singleton {

private static Singleton instance = new Singleton(); //外界无法访问

private Singleton() { //客户对象无法创建

}

public static Singleton getInstance () { //全局访问点

return instance;

}

}

  [code]

注意 1. instance没有直接暴露给外界

 2. 此实现是线程安全,当多个线程同时去访问该类的getInstance方法时,不会初始化多个对象,

    因为JVM在加载此类时,对于static属性的初始化只能由一个线程执行且仅一次。

     3. 客户端使用简便: Singleton singleton = Singleton.getInstance();

# 3.3 进阶

## 3.3.1 迟延创建

- 只有在第一次使用该类的实例化时才去实例化。

->> 把单例的实例化个过程移至getInstance方法即可,而不是在加载类时预先创建。

- [code]

public class UnThreadSaftSingleton {

private UnThreadSaftSingleton instance;

public static UnThreadSaftSingleton getInstance () {

if (instance == null) {

instance = new UnThreadSaftSingleton();

}

return instance;

}

}

[code]

## 3.3.2 线程安全

注意: 1. 高并发环境中,线程不安全的,会产生多个指向该类的实例,并出现内存泄漏的情况。

2. 解决该问题,只需要对getInstance方法加 synchronized 关键字。

## 3.3.3 Double-Check Locking

- synchronized 性能有问题 --> 对整个getInstance方法进行同步是没有必要的

- 只要保证被实例化的那段逻辑被一个线程执行就OK了,而返回引用的那段代码则没必要同步

[code] 

public class DoubleCheckSingleton {

private valotile static DoubleCheckSingleton instance = null;

public static DoubleCheckSingleton getInstance () {

if(instance == null) {

synchronized(DoubleCheckSingleton.class) { //synchronize creation block

if (instance == null) {

instance = new DoubleCheckSingleton();

}

}

}

return instance;

}

}

[code]

注意: 1. 锁住初始化代码块

2. 两次判断,故称 Double checked Locking

3. 属性instance是被volatile修饰的。 作用:线程能够自动发现volatile变量的最新值

4. 此程序只有在Java 5 及以上版本才能运行

## 3.3.4 Initialization on demand holder

- 另一种实现线程安全的单例模式

[code]

public class LazyLoadedSingleton {

private LazyLoaderSingleton () {

}

private static class LazyHolder {

private static final LazyLoadedSingleton singletonInstance = 

new LazyLoadedSingleton();

}

public static LazyLoadedSingleton getInstance () {

return LazyHolder.singletonInstance;

}

}

[code]

注意:只有第一调用 getInstance 时才会加载。

## 3.3.5 Singleton的序列化

- 如果Singleton实现了Serializable接口,特别需要注意:

在默认情况下,每次反序列化总会创建一个新的实例对象,这样一个系统就会出现多个对象可供使用。

- 需要在readResolve method 里面做文章

[code]

public class SerialibleSingleton implements Serializable {

private static final long serialVersionUID = 1L;

static SerialibleSingleton instance = new SerialibleSingleton();

private SerialibleSingleton(){

}

//This method is called immediately after an object of this class deserialized.

//This method return the singleton instance.

private Object readResolve () {

return instance;

}

}

[code]

- 这样内存中始终保存一个对象

# 3.5 总结

- 基于同一个Jvm中,如何保证一个类只有一个实例

- 如果在分布式环境中,可能需要考虑如何保证在整个应用(可能分布在不同的JVM上)只有一个实例。

 

==思路清晰,简单易懂,又不失深度,好书==

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值