【问题标题】:Case Study: Singleton class inheritance - Good or bad?案例研究:单例类继承——好还是坏?
【发布时间】:2014-01-10 07:07:36
【问题描述】:

下面有一个单例类继承的示例代码。但是,我没有预见到此代码是否会出现任何隐藏问题。谁能分析一下,给个提示?

interface ChairIF {
    public int getLeg();

    public void test();
}

class ChairImpl implements ChairIF {

    private static final Lock lock = new ReentrantLock();
    private static ChairIF instance = null;

    public static ChairIF getInstance(String clazzName) {
        //get class by clazzName
        Class clazz = null;
        try {
            clazz = Class.forName(clazzName);
        } catch (ClassNotFoundException ex) {
            lock.lock();
            try {
                if (instance == null) {
                    instance = new ChairImpl();
                }
            } finally {
                lock.unlock();
            }
        }

        //init singleton instance of clazzName
        if (instance == null) {
            lock.lock();

            try {
                if (instance == null) {
                    instance = (ChairIF) clazz.newInstance();
                } else {
                    if (instance.getClass() != clazz) {
                        instance = (ChairIF) clazz.newInstance();
                    }
                }
            } catch (Exception ex) {
                instance = new ChairImpl();
            } finally {
                lock.unlock();
            }
        } else {
            lock.lock();
            try {
                if (!instance.getClass().getName().equals(clazz.getName())) {
                    instance = (ChairIF) clazz.newInstance();
                }
            } catch (Exception ex) {
                instance = new ChairImpl();
            } finally {
                lock.unlock();
            }
        }

        return instance;
    }


    public int getLeg() {
        return 4;
    }

    public void test() {
        throw new UnsupportedOperationException();
    }
}

class ThreeLegChair extends ChairImpl {
   public ThreeLegChair() {}

   public int getLeg() {
      return 3;
   }

   public void test() {
      int i = 0;

      while(i < 10000) {
         System.out.println("i: " + i++);
      }
   }
}

class NoLegChair extends ChairImpl {
   public NoLegChair() {}

   public int getLeg() {
      return 0;
   }

   public void test() {
      int j = 0;

      while(j < 5000) {
         System.out.println("j: " + j++);
      }
   }
}

public class Test {
   public static void main(String[] args) {
     System.out.println(ChairImpl.getInstance("ThreeLegChair").getLeg());
     System.out.println(ChairImpl.getInstance("NoLegChair").getLeg());

     /***
     TODO: build logic to run 2 test() simultaneously.
     ChairImpl.getInstance("ThreeLegChair").test();
     ChairImpl.getInstance("NoLegChair").test(); 
     ****/
   }
}

如您所见,我确实将一些测试代码放在了 2 个子类中。 ThreeLegChair 是从 0 到 10000 循环并打印出来。 NoLegChair 是只循环从 0 到 5000 并打印出来。

我在控制台日志中得到的结果是正确的。 ThreeLegChair 打印 i 从 0 到 10000。NoLegChair 打印 j 从 0 到 5000。

请分享你的想法:)

【问题讨论】:

  • 措辞优美的好例子,这应该作为如何提问的例子发布..
  • 这...不是单身人士。
  • (如果是,你不能继承它)

标签: java inheritance singleton


【解决方案1】:

单例模式是使用私有构造函数的概念实现的,即类本身负责创建类的单个实例(单例)并防止其他类创建对象。

现在构造函数是private你不能首先继承单例类在您的情况下,我没有看到私有构造函数,这使得它容易受到其他类访问它的对象创建的影响。

单例模式示例:

  • 在 Java 中使用枚举
enum SingletonEnum {
  SINGLE_INSTANCE;
  public void doStuff() {
      System.out.println("Singleton using Enum");
  }
}
  • 惰性初始化方法

类 SingletonClass {

  private static SingletonClass singleInstance;

  private SingletonClass() {
      // deny access to other classes
  }

  // The object creation will be delayed until getInstance method is called.
  public static SingletonClass getInstance() {

      if (null == singleInstance) {
          // Create only once
          singleInstance = new SingletonClass();
      }

      return singleInstance;
  }
}

但是,上面的示例可能无法保证多线程环境中的单例行为。推荐使用double checked locking机制来保证你已经创建了这个类的单个实例。

【讨论】:

  • 在 Java 中,实现单例的首选方法是使用 enum,实际上无需处理它(尤其是您在编辑中添加的多线程部分)。
  • 是的,我完全同意你的观点。
  • @BrianRoach :在我的帖子中添加了枚举示例。
  • 谢谢各位,重点关注继承,我忘了singleton最重要的事情了:)
【解决方案2】:

您发布的代码不是单例模式的实现。

很简单,你可以这样做:

ChairImpl ci = new ChairImpl();

并根据需要实例化任意数量。

实现单例模式的传统方法是将构造函数设为私有,有一个私有静态字段来保存类的单个实例,以及一个静态getInstance() 方法,该方法要么实例化该实例,要么返回现有实例。使该线程安全涉及将其声明为synchronized 或使用锁定方案。

私有构造函数位使得你不能从它继承。

也就是说,在 Java 中,首选方式是使用 enum,它免费提供所有困难的部分:

public enum MySingleton {
    INSTANCE;

    public int getLeg() {
        return 4;
    }
}

并用作:

MySingleton ms = MySingleton.INSTANCE;
int leg = ms.getLeg();

【讨论】:

    【解决方案3】:

    单例通常有私有构造函数。您的班级没有遵循正确的单例模式。否则你不会继承你的单例类。

    【讨论】:

      猜你喜欢
      • 2012-01-23
      • 2013-06-02
      • 2020-11-08
      • 1970-01-01
      • 2020-10-25
      • 1970-01-01
      • 2010-09-25
      • 2019-07-12
      • 1970-01-01
      相关资源
      最近更新 更多