(二)、创建者模式(5种)
创建者模式的主要关注点: “怎么创建对象”,它的主要特点是:“将对象的创建和使用分离
”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。
1.单列模式
单列模式 是Java中最简单的设计模式之一。这种类型的设计属于创建型模式,他提供了一种创建对象的最佳方式。
这种模式会涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其他唯一的方式,可以直接访问,不需要实列化该类的对象。
(1).单列模式的结构
单列模式饿主要有以下角色:
- 单列模式。只能创建一个实列的类
- 访问类。使用单列类
(2).单列模式的实现
单列设计模式分类两种:
- 饿汉式:
类加载就会导致该单实列对象被创建
(加载的时候就创建) - 懒汉式: 类加载不会导致该单列对象被创建,而是
首次使用该对象时才会创建
。
(3).饿汉式的两种方式
- 饿汉式-方式一 (静态变量方式)
单列模式
package com.jsxs.pattern.singletion.demo1; /** * @Author Jsxs * @Date 2023/4/16 14:11 * @PackageName:com.jsxs.pattern.singletion.demo1 * @ClassName: Singletion * @Description: TODO 静态成员变量 * @Version 1.0 */ public class Singletion { // 1.私有构造方法: 外界不能创建这个对象也就是->new private Singletion() { } //2.在本类中创建该类的对象: private->外界不能直接访问。 static->设置为静态的变量,目的是为了让静态方法获取。 private static Singletion singletion=new Singletion(); //3.提供一个公共的访问方式,让外界获取该对象 public static Singletion getInstance(){ return singletion; } }
访问类
package com.jsxs.pattern.singletion.demo1; /** * @Author Jsxs * @Date 2023/4/16 14:21 * @PackageName:com.jsxs.pattern.singletion.demo1 * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { //1.创建Singletion类的对象 Singletion instance = Singletion.getInstance(); Singletion instance1 = Singletion.getInstance(); // 2.判断创建得到这两个对象是否是一个对象 System.out.println(instance==instance1); // == 判断的时地址 } }
- 饿汉式-方式二 (静态代码块)
package com.jsxs.pattern.singletion.demo2; /** * @Author Jsxs * @Date 2023/4/16 14:30 * @PackageName:com.jsxs.pattern.singletion.demo2 * @ClassName: Singleton * @Description: TODO 饿汉式2- 静态代码块---- 静态变量和静态代码块谁先声明谁先执行。 * @Version 1.0 */ public class Singleton { // 1.私有构造方法 private Singleton(){} //2.声明Singleton类型的变量 private static Singleton instance; // 并未初始化 //3.静态代码块中进行赋值 static { instance=new Singleton(); } //4.对外提供该类对象的方法 public static Singleton getInstance(){ return instance; } }
package com.jsxs.pattern.singletion.demo2; /** * @Author Jsxs * @Date 2023/4/16 14:34 * @PackageName:com.jsxs.pattern.singletion.demo2 * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance==instance1); } }
说明: 该方式在成员位置声明Singleton类型的静态变量,而对象的创建时在静态代码块中,也是对着类的加载而创建。所以和饿汉式的方式1基本一样,当然该方式也存在内存浪费的问题。
(4).懒汉式的七种方式
- 饿汉式-方式1 (静态方式-线程不安全)
package com.jsxs.pattern.singletion.demo3; /** * @Author Jsxs * @Date 2023/4/16 14:43 * @PackageName:com.jsxs.pattern.singletion.demo3 * @ClassName: Singleton * @Description: TODO 懒汉式-1 * @Version 1.0 */ public class Singleton { // 1.私有构造方法 private Singleton(){} // 2.声明Singleton类型的变量---*******并没有赋值的操作 private static Singleton instace; //3.对外提供访问方式 public static Singleton getInstance(){ if (instace==null){ //1.如果以前没有创建对象,那么就创建一个对象。如果创建过,那么就直接返回我们第一次创建的对象。 instace=new Singleton(); } return instace; } }
package com.jsxs.pattern.singletion.demo3; /** * @Author Jsxs * @Date 2023/4/16 14:50 * @PackageName:com.jsxs.pattern.singletion.demo3 * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { System.out.println( Singleton.getInstance().hashCode()); Singleton instance1 = Singleton.getInstance(); System.out.println(instance1.hashCode()); } }
我们发现在单线程的情况下: 哈希值是一样的也就是对象是一样的
问题: 多线程
的情况下: 会出现哈希值的不一致->对象不一致。
package com.jsxs.pattern.singletion.demo3; /** * @Author Jsxs * @Date 2023/4/16 14:43 * @PackageName:com.jsxs.pattern.singletion.demo3 * @ClassName: Singleton * @Description: TODO 懒汉式-1 * @Version 1.0 */ public class Singleton { // 1.私有构造方法 private Singleton(){} // 2.声明Singleton类型的变量---*******并没有赋值的操作 private static Singleton instace; //3.对外提供访问方式 public static Singleton getInstance(){ if (instace==null){ //1.如果以前没有创建对象,那么就创建一个对象。如果创建过,那么就直接返回我们第一次创建的对象。 try { Thread.sleep(2000); //等待2秒 } catch (InterruptedException e) { e.printStackTrace(); } instace=new Singleton(); } return instace; } }
package com.jsxs.pattern.singletion.demo3; /** * @Author Jsxs * @Date 2023/4/16 14:50 * @PackageName:com.jsxs.pattern.singletion.demo3 * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { new Thread(()->{ System.out.println( Singleton.getInstance().hashCode()); }).start(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance1.hashCode()); } }
- 懒汉式-2 (线程安全)
这里我们在创建对象的时候只是添加了 同步锁Synchronized
package com.jsxs.pattern.singletion.demo3; /** * @Author Jsxs * @Date 2023/4/16 14:43 * @PackageName:com.jsxs.pattern.singletion.demo3 * @ClassName: Singleton * @Description: TODO 懒汉式-2 (线程安全) * @Version 1.0 */ public class Singleton { // 1.私有构造方法 private Singleton(){} // 2.声明Singleton类型的变量---*******并没有赋值的操作 private static Singleton instace; //3.对外提供访问方式 public static synchronized Singleton getInstance(){ // -**********添加了同步锁: "没有执行完毕,不释放资源" if (instace==null){ //1.如果以前没有创建对象,那么就创建一个对象。如果创建过,那么就直接返回我们第一次创建的对象。 try { Thread.sleep(2000); //等待2秒 } catch (InterruptedException e) { e.printStackTrace(); } instace=new Singleton(); } return instace; } }
package com.jsxs.pattern.singletion.demo3; /** * @Author Jsxs * @Date 2023/4/16 14:50 * @PackageName:com.jsxs.pattern.singletion.demo3 * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { new Thread(()->{ System.out.println( Singleton.getInstance().hashCode()); }).start(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance1.hashCode()); } }
说明: 该方式实现了懒加载的效果,同时又解决了线程安全问题。但是在GetInstance()方法上添加Synchronized关键字,导致该方法的执行效率特别低。从上面的代码我们可以看出,其实就是在初始化inatance的时候才会出现线程安全问题,一旦初始化完成就不存在了。