java单例设计模式

单例字典的含义:正在考虑的单一的人或事物。

Java单例设计模式被认为是最简单的设计模式之一。它属于创意设计模式类别。

Singleton设计模式仅声明应仅创建单个对象,并且它将被所有其他类使用。

单例设计模式通常用于日志记录、缓存、驱动程序对象、线程池等。它也用于其他设计模式,如抽象工厂、立面、构建器、原型等。

如何创建单例设计模式?

单例设计模式可以以不同的方式实现,但概念对所有人都是一样的。

  • 私有构造函数: 私有构造函数用于防止从其他类实例化类。
  • 私有静态变量: 私有静态变量将包含类的实例。
  • 公共静态方法: 公共静态方法是其他类获取单例类实例的全局访问点。它将返回singleton类的实例。

让我们讨论用不同的方法实现单例设计模式。

急切的初始化

如果渴望初始化,则在类加载时创建singleton类的实例。

示例:

  1. package com.codesjava;
  2. public class SingletonTest {
  3. private static final SingletonTest instance = new SingletonTest();
  4. //Private constructor to prevent instantiation of the class from other classes.
  5. private SingletonTest() {}
  6. public static SingletonTest getInstance() {
  7. return instance;
  8. }
  9. }

急切初始化方法的问题:
正如我们所讨论的,singleton类的实例是在类加载时创建的。因此,可能存在客户端应用程序不使用对象但仍创建对象的情况。急切初始化方法的另一个问题是我们没有任何方法来处理异常。

静态块初始化

实现单例设计模式的静态块初始化方法与具有异常处理功能的急切初始化方法几乎相同。

示例:

  1. package com.codesjava;
  2. public class SingletonTest {
  3. private static final SingletonTest instance;
  4. //Private constructor to prevent instantiation of the class from other classes.
  5. private SingletonTest() {}
  6. //Static block initialization
  7. static {
  8. try {
  9. instance = new SingletonTest();
  10. } catch(Exception e) {
  11. throw new RuntimeException("Exception occured.");
  12. }
  13. }
  14. public static SingletonTest getInstance() {
  15. return instance;
  16. }
  17. }

静态块初始化方法的问题:
它用急切的初始化方法解决了异常处理问题,但是在使用它之前的对象创建仍然存在。

延迟初始化

实现单例设计模式的惰性初始化方法解决了在使用对象之前创建对象的问题。在这种方法中,我们将在全局访问方法中创建实例。

示例:

  1. package com.codesjava;
  2. public class SingletonTest {
  3. private static SingletonTest instance;
  4. //Private constructor to prevent instantiation of the class from other classes.
  5. private SingletonTest() {}
  6. public static SingletonTest getInstance() {
  7. if (instance == null) {
  8. instance = new SingletonTest();
  9. }
  10. return instance;
  11. }
  12. }

延迟初始化方法的问题:
延迟初始化方法可能不起作用,并可能在多线程环境中引起问题。如我们所见,getInstance() 方法没有锁,因此如果两个线程正在访问getInstance() 方法同时,他们可以得到两个不同的对象,这将打破单例概念。

线程安全方法

实现单例设计模式的线程安全方法将解决多线程问题。我们必须创建一个线程安全的单例类,为此我们可以创建全局访问方法。在这种情况下,当一个线程执行getInstance() 方法时,其他线程必须等待。我们也可以使用同步块,这是一个更好的选择。

同步方法示例

  1. package com.codesjava;
  2. public class SingletonTest {
  3. private static SingletonTest instance;
  4. //Private constructor to prevent instantiation of the class from other classes.
  5. private SingletonTest() {}
  6. public static synchronized SingletonTest getInstance() {
  7. if (instance == null) {
  8. instance = new SingletonTest();
  9. }
  10. return instance;
  11. }
  12. }

具有同步块的示例

  1. package com.codesjava;
  2. public class SingletonTest {
  3. private static SingletonTest instance;
  4. //Private constructor to prevent instantiation of the class from other classes.
  5. private SingletonTest() {}
  6. //Synchronized block with double checked locking principle
  7. public static SingletonTest getInstance() {
  8. if (instance == null) {
  9. synchronized (SingletonTest.class) {
  10. if(instance == null){
  11. instance = new SingletonTest();
  12. }
  13. }
  14. }
  15. return instance;
  16. }
  17. }

Bill Pugh单例实施

它是实现单例设计模式的最广泛使用的方法。它使用私有内部静态帮助程序类创建单例类。内部静态类将包含singleton类对象。它不会加载singleton类,它将在第一次调用getInstance() 方法时加载。

注意: Bill Pugh单例实现方法不需要同步。

示例:

  1. package com.codesjava;
  2. public class SingletonTest {
  3. //Private constructor to prevent instantiation of the class from other classes.
  4. private SingletonTest() {}
  5. private static class SingletonHelper {
  6. private static final SingletonTest INSTANCE = new SingletonTest();
  7. }
  8. public static SingletonTest getInstance() {
  9. return SingletonHelper.INSTANCE;
  10. }
  11. }

使用反射破坏单例模式

根据Java文档: 反射使Java代码能够发现有关加载类的字段、方法和构造函数的信息,并使用反射字段、方法和构造函数对其底层对应项进行操作,在安全限制范围内。

我们可以使用反射来破坏上述所有方法来实现单例设计模式。

示例:

  1. package com.codesjava;
  2. import java.lang.reflect.Constructor;
  3. class SingletonTest {
  4. private static final SingletonTest instance = new SingletonTest();
  5. //Private constructor to prevent instantiation of the class from other classes.
  6. private SingletonTest() {}
  7. public static SingletonTest getInstance() {
  8. return instance;
  9. }
  10. }
  11. public class SingletonTestWithReflection {
  12. public static void main(String[] args) {
  13. SingletonTest instance1 = SingletonTest.getInstance();
  14. SingletonTest instance2 = null;
  15. try {
  16. Constructor[] constructors = SingletonTest.class.getDeclaredConstructors();
  17. for (Constructor constructor : constructors) {
  18. constructor.setAccessible(true);
  19. instance2 = (SingletonTest) constructor.newInstance();
  20. break;
  21. }
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. System.out.println(instance1.hashCode());
  26. System.out.println(instance2.hashCode());
  27. }
  28. }

输出:

  1. 366712642
  2. 1829164700

注意: 您可以清楚地看到两个对象的哈希代码是不同的,这打破了单例设计模式的概念。为了克服这个问题,我们应该使用枚举来实现单例设计模式,因为枚举值只实例化一次。

单例设计模式中的序列化

我们可以序列化一个单例对象,但是在反序列化的情况下,它将返回一个新对象,这将破坏单例设计模式的概念。为了克服这个问题,我们需要提供Readparse () 方法这加强了单例模式。

  1. package com.codesjava;
  2. import java.io.Serializable;
  3. public class SingletonTest implements Serializable {
  4. //Private constructor to prevent instantiation of the class from other classes.
  5. private SingletonTest() {}
  6. private static class SingletonHelper {
  7. private static final SingletonTest INSTANCE = new SingletonTest();
  8. }
  9. public static SingletonTest getInstance() {
  10. return SingletonHelper.INSTANCE;
  11. }
  12. protected Object readResolve() {
  13. return getInstance();
  14. }
  15. }

java原型设计模式

字典原型的含义:开发其他形式的设备或车辆的第一个或初步版本。

Java原型设计模式属于创建设计模式类别,它用于创建新对象成本高的情况。

Java原型设计模式指出,如果创建新对象的成本比克隆原始对象然后对其进行修改 (而不是创建新对象) 要高。

让我们想象一下,我们有一个从数据库加载的客户对象,加载后我们必须多次修改其数据。在这种情况下,我们必须克隆该对象,而不是创建新对象并再次从数据库加载所有数据。

示例

客户。java

  1. package com.codesjava;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. public class Customers implements Cloneable {
  5. private List<String> customerList;
  6. public Customers() {
  7. customerList = new ArrayList<String>();
  8. }
  9. public Customers(List<String> list) {
  10. this.customerList=list;
  11. }
  12. public void loadDataFromDB() {
  13. //Read all customers from DB
  14. customerList.add("Bharat");
  15. customerList.add("Sahdev");
  16. customerList.add("Richi");
  17. customerList.add("Jai");
  18. customerList.add("Bharti");
  19. customerList.add("Saveta");
  20. customerList.add("Deepika");
  21. }
  22. public List<String> getCustomerList() {
  23. return customerList;
  24. }
  25. @Override
  26. public Object clone() throws CloneNotSupportedException {
  27. List<String> temp = new ArrayList<String>();
  28. for (String string : this.getCustomerList()) {
  29. temp.add(string);
  30. }
  31. return new Customers(temp);
  32. }
  33. }

原型模式测试

  1. package com.codesjava;
  2. import java.util.List;
  3. public class PrototypePatternTest {
  4. public static void main(String args[]) {
  5. try {
  6. Customers customers = new Customers();
  7. customers.loadDataFromDB();
  8. Customers customers1 = (Customers) customers.clone();
  9. Customers customers2 = (Customers) customers.clone();
  10. List<String> customersList1 = customers1.getCustomerList();
  11. customersList1.add("Vivek");
  12. List<String> customersList2 = customers2.getCustomerList();
  13. customersList2.remove("Deepika");
  14. System.out.println("customers List elements: " + customers.getCustomerList());
  15. System.out.println("customers1 List elements: " + customersList1);
  16. System.out.println("customers2 List elements: " + customersList2);
  17. } catch (CloneNotSupportedException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. }

输出

  1. customers List elements: [Bharat, Sahdev, Richi, Jai, Bharti, Saveta, Deepika]
  2. customers1 List elements: [Bharat, Sahdev, Richi, Jai, Bharti, Saveta, Deepika, Vivek]
  3. customers2 List elements: [Bharat, Sahdev, Richi, Jai, Bharti, Saveta]