我正在寻找一种方法来实现一个抽象类(或有效抽象),它只强制执行每个子类的一个实例。
我很确定使用Factory实现它会非常简单,但我很想知道是否可以在不知道所有子类类型的情况下完成,即通用的单例执行器类。
现在我大多只是想要这样的想法,所以我不是在寻找对这里的设计选择提出疑问的反馈。
我正在使用的语言是Java,但是现在我不一定担心实现细节,除非在Java中不可能,否则当然会提供证据证明它不可能。
答案 0 :(得分:0)
我想知道你想要做什么。我想到了几种可能性,并且知道它的发展方向可能有所帮助。
选项1
因此,您可以尝试使用enum
类型作为抽象基类。然后,每个枚举常量由语言保证为单例。枚举可以有常量实现的抽象方法。如果您有很多实现常量和许多抽象方法要实现,那么这将起作用,但编译单元变得非常大并且难以导航。如果它开始失控,你当然可以将一些工作委托给辅助类。
选项2
你可以做的是让基类构造函数检查它的实际类型并将其存储在静态HashSet(或类似的)中。如果条目已存在,那么您有两个相同单例的实例。像
这样的东西public abstract class BaseClass {
private static HashSet<Class<?>> instances = new HashSet<>();
protected BaseClass() {
checkInstances();
}
private synchronized void checkInstances() {
boolean duplicate = instances.add(getClass());
if (duplicate) {
throw new RuntimeException("Duplicate class " + getClass().getName());
}
}
}
这样做的缺点是错误发生在运行时并且代码不是特别漂亮,你可以看到你可能需要考虑集合的同步
选项3
您的最终选择是不要求基类强制执行此限制。派生类的工作可能应该决定它们是否是单身人士。派生类中的私有构造函数是最简单的方法。
<强>结论强>
我个人会实现选项1或选项3,因为您不会遇到运行时故障。
答案 1 :(得分:0)
首先,一般的单身人士没有意义 父类不应负责检索和管理其子类的实例 它以两种方式创建强耦合(parent-&gt; child和child-&gt; parent)。
其次,正如shmosel所说,不可能对单例进行子类化(没有特殊的工件)
单例模式的关键是缺乏在单例类之外实例化类的能力,因此不必提供公共构造函数。
在这些条件下,如何对单例类进行子类化?
要允许对单例类进行子类化,您必须拥有公共构造函数,同时确保您只有一个类的实例。
诸如Spring之类的控制容器的反转可能会这样做(这是一个特殊工件的例子)。
作为旁注,我不考虑访问修饰符调整,例如package-private
修饰符,它可以允许对单例进行子类化,但是它的限制是单例只是在单例之外的单例封装
答案 2 :(得分:-1)
我想说,单身人士很糟糕。但发现这个问题很有趣,所以我创造了你想要的东西。 这是代码
public static abstract class SingletonBase {
private static HashSet<SingletonBase> instances = new HashSet<>();
{
for (SingletonBase sb : instances) {
if (sb.getClass() == this.getClass()) throw new RuntimeException("there is already 1 instance");
}
}
public static <E> E getInstance(Class<E> clazz) {
if (!SingletonBase.class.isAssignableFrom(clazz)) {
throw new RuntimeException();
}
for (SingletonBase sb : instances) {
if (sb.getClass() == clazz) return (E) sb;
}
try {
return clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
private SingletonBase() {
instances.add(this);
}
}
static class SingletonTest extends SingletonBase{
}
static class SecondSingletonTest extends SingletonBase{
}
public static void main(String[] args) {
for(int i=0;i<=10;i++)
System.out.println( SingletonBase.getInstance(SingletonTest.class));
for(int i=0;i<=10;i++)
System.out.println( SingletonBase.getInstance(SecondSingletonTest.class));
//throws exception, because we try to create second instance here
new SingletonTest();
}
创建泛型类的方法存在一些问题,这些问题在此解决: 首先,您不能创建多个实例,因此基类必须跟踪所有实例,当您尝试使用new创建另一个实例时,它将抛出异常。其次,您需要获取特定类的实例。如果您不想创建这样的实例:
SingletonBase.getInstance(SecondSingletonTest.class)
您可以像这样创建子类:
static class SingletonTest extends SingletonBase{
public static SingletonTest getInstance(){
return getInstance(SingletonTest.class);
}
}
还有人建议使用ENUM方法,它很容易实现,但是从SOLID打破封闭原则