设计模式分类
创建型模式
用于描述“怎样创建对象”,它的主要特点是将对象的创建与使用分离 GoF (四人组) 书中提供了单例,原型,工厂方法,抽象工厂,建造者等 5种创建型模式
单例设计模式
单例模式概念
单例模式 是JAVA 中最简单的设计模式之一 这种类型的设计模式属于创建型模式 他提供了一种创建对的最佳方式
这种模式设计一个单一的类 该类负责创建自己的对象 用时确保只有单个对象被创建 这个类提供了一种访问其唯一的对象的方式。
单例模式的实现
饿汉式
饿汉式:类加载就是导致该单实例对象被创建
类加载的时候,就开始初始化instance,即一上来就new;
/** * 饿汉式 静态成员变量 */
public class Pattern {
//1,创建静态的私有构造方法
private Pattern() {
}
//2.内部创建类的对象
//4.要求此对象也必须声明为静态的
private static Pattern pattern= new Pattern();
//3,对外提供一个公共访问的对象
public static Pattern getInstance() {
return pattern;
}
}
结果
public class Demo {
public static void main(String[] args) {
Pattern instance = Pattern.getInstance();
Pattern instance1 = Pattern.getInstance();
System.out.println(instance==instance1);
}
}
说明
该方法在成员位置声明 Pattern 类的的静态变量 并创建Pattern 类的对象pattern 。pattern 对象时随这类的加载而创建的 如果对象足够大的话 而一直没有使用就会造成内存的浪费。
饿汉式的枚举实现
枚举类实现单例模式是线程安全的 并且只会装载一次 设计者充分的利用了枚举的这个特性来实现单例模式 枚举的写法非常简单 而且枚举类型是所用的单例实现中唯一一种不会被破坏的单例实现模式
package Singleton;
/** * 枚举方式 */
public enum SingDemo1 {
INSTANCE;
}
懒汉式
类加载不会导致该单实例对象被创建 而是首次使用该对象时才会创建
懒汉式线程不安全
package Singleton;
/** * 懒汉式 线程不安全 */
public class Singleton {
// 私有的构造方法
private Singleton() {
}
// 声明Singleton 类型的变量instance
private static Singleton instance; // 只是声明一个该类型的变量 并没有进行赋值
// 对外提供访问方式
public static Singleton getInstance() {
instance = new Singleton();
return instance;
}
}
结果
懒汉式实现二 线程安全模式
修改Singleton 确保只有一次对象的创建
public class Singleton {
// 私有的构造方法
private Singleton() {
}
// 声明Singleton 类型的变量instance
private static Singleton instance; // 只是声明一个该类型的变量 并没有进行赋值
// 对外提供访问方式
public static Singleton getInstance() {
//判断 instance 是否为null 如果是null 说明还么有创建 Singleton 类的对象
// 如果没有 创建一个并返回 如果有 就直接返回
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这样虽然是true 但是任然不是安全的 如果是多线程模式的话是不安全的 还需要改进上面的代码就是懒汉式的线程安全的模式
public class Singleton {
// 私有的构造方法
private Singleton() {
}
// 声明Singleton 类型的变量instance
private static Singleton instance; // 只是声明一个该类型的变量 并没有进行赋值
// 对外提供访问方式
public static synchronized Singleton getInstance() {
//判断 instance 是否为null 如果是null 说明还么有创建 Singleton 类的对象
// 如果没有 创建一个并返回 如果有 就直接返回
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
懒汉式方式3(双重检查锁)
对于getInstance() 方法来说 绝大部分的操作都是读的操作 读操作是线程安全的 所以我们没必要每个线程必须持有锁才能调用该方法 我们需要调整加锁的时机 由此也产生了一种新的实现模式 :双重检查锁模式
/** * 双重检查锁模式 */
public class SingDemo {
// 构造方法
private SingDemo() {
}
// // 声明Singleton 类型的变量instance
private static SingDemo instance;
// 对外提供公共的方法
public static SingDemo getInstance() {
if (instance == null) {
synchronized (SingDemo.class) {
if (instance == null) {
instance = new SingDemo();
}
}
}
return instance;
}
}
双重检查锁模式是一种非常好的单例实现模式 解决了单例,性能,线程安全的问题 上面的双重检测锁模式看上去完美无缺 其实是存在问题 在多个线程的情况下 可能会出现空指针问题 出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排的操作 要解决双重检查锁模式带来空指针异常的问题只主要需要加volatitle 关键字 可以保证可见性和有序性
小结:
添加volatitle 关键字之后的双重检查锁模式是一种比较好的单例实现的模式 能够保证在多线程的情况下线程安全也不会有性能问题。
懒汉式实现方式四 (静态内部类方式)
静态内部类单例模式中实例由内部类创建 由于JVM 在加载外部类的过程中 是不是加载静态内部类的 只有内部类的属性/ 方法 被调用时才会被加载并初始化其静态属性 静态属性由于被static 修饰 保证只被实例化一次并且严格保证实例化顺序。
/** * 静态内部类 */
public class SingDemo1 {
// 私有的构造方法
private SingDemo1() {
}
// 定义一个静态的内部类
private static class Sing {
// 在内部类中声明并初始化外部类的对象
private static final SingDemo1 INSTANCE =new SingDemo1();
}
// 对外提供公共的访问方式
public static SingDemo1 getInstance() {
return Sing.INSTANCE;
}
}
说明
第一次加载 该类的时候不会去初始化INSTANCE 只有在第一次调用的 getInstance 虚拟机加载 Sing 并初始化 INSTANCE 这样不仅能确保线程安全 也能保证 该类的唯一性。
总结
静态内部类单例模式是一种优秀的单例模式 是开源项目中比较常用的一种单例的模式 在没有任何锁的情况下 保证了多线程下的安全性 并且没有任何性能影响和空间的浪费。
破坏单例模式
单例模式总结
1,单例类只能有一个实例
2,private Constructor() {}
3,内部创建类的对象
4,提供public static 的方法 返回类的对象
5,此对象也必须声明为static
结构型模式
用于描述如何将类或者对象按某种布局组成更大的结构,GOF(四人组)书中提供了代理,适配器,桥接,装饰,外观,享元,组合等 7种结构型模式
行为型模式
用于描述类或者对象之间怎样相互协作共同完成单个对象无法完成的任务,以及怎样分配职责GOF (四人组)书中提供了 方法 策略 命令 职责链 状态 观察者 中介者 迭代器 访问者 备忘录 解释器 等 11中行为型模式
文章评论