Java中的单例和继承
我有一个基类,它捕获了两个类共有的一些功能。换句话说,我可以创建一个基类,并使这两个类成为该基类的子类。但是,对于这些子类中的每一个子类,可以创建的实例数为1(即,每个子类必须是单例)。 我在谷歌上搜索了一下,发现关于这个问题有一个合理的争论。虽然有几种解决方案,但我不确定它们是否适合我的情况Java中的单例和继承,java,design-patterns,inheritance,singleton,Java,Design Patterns,Inheritance,Singleton,我有一个基类,它捕获了两个类共有的一些功能。换句话说,我可以创建一个基类,并使这两个类成为该基类的子类。但是,对于这些子类中的每一个子类,可以创建的实例数为1(即,每个子类必须是单例)。 我在谷歌上搜索了一下,发现关于这个问题有一个合理的争论。虽然有几种解决方案,但我不确定它们是否适合我的情况 有谁能告诉我应该如何设计它吗?您可以将每个类单独设置为一个单例,并将基类抽象化。不确定争论的是什么——只是一般来说,单身并不是一个好主意?使用。有一个单独的类,其中包含检索单例的方法,并让它在实例变量或映
有谁能告诉我应该如何设计它吗?您可以将每个类单独设置为一个单例,并将基类抽象化。不确定争论的是什么——只是一般来说,单身并不是一个好主意?使用。有一个单独的类,其中包含检索单例的方法,并让它在实例变量或映射中保存对单例的引用 您可能不希望增加复杂性,但是像这样的框架是为了解决这类问题而创建的 这似乎是活的,很好,它可能是最简单的,但仍然是固溶体。看看控制反转主题,让框架在需要的地方注入单例 简言之,不要试图让单身汉管理对自己的访问。把它委托给其他人
具有复杂继承的单例类本身并没有什么错。事实上,带有私有构造函数(无实例)的类层次结构在许多情况下都非常有用。您只需决定如何管理Singleton的两个重要方面:创建和访问。我不是Java方面的专家,所以我不知道这在技术上是否是合法的Java代码(也许其他海报可以评论): 使基类从泛型类Singleton继承 例如:
class Singleton<T> {
protected Singleton(); //constructor
private static T _instance;
}
class DerivedOne extends Singleton<DerivedOne>{
protected DerivedOne(){} //constructor
}
class DerivedTwo extends Singleton<DerivedTwo>{
protected DerivedTwo(){} //constructor
}
类单例{
受保护的Singleton();//构造函数
私有静态T_实例;
}
类DerivedOne扩展了Singleton{
受保护的DerivedOne(){}//构造函数
}
类DerivedTwo扩展了Singleton{
受保护的DerivedTwo(){}//构造函数
}
我不知道您是否需要一个示例,但我尝试了一下。不知道你的任何细节,这个例子是非常模糊的。我也在这里学习,所以让我们知道你最终实现了什么
基类:
public abstract class BaseClass {
public void someMethod() {
System.out.println("base class hello: " + this);
}
public abstract void someOtherMethod(String value);
}
其中一个子类:
public class SubClassOne extends BaseClass {
private static SubClassOne instance;
private SubClassOne() {}
public static SubClassOne getInstance() {
if (instance == null) {
instance = new SubClassOne();
}
return instance;
}
public void someOtherMethod(String value) {
someMethod();
System.out.println("sub class hello: " + value + " " + this);
}
public static void main(String[] args) {
SubClassOne one = SubClassOne.getInstance();
SubClassOne two = SubClassOne.getInstance();
SubClassOne three = SubClassOne.getInstance();
SubClassOne four = SubClassOne.getInstance();
one.someOtherMethod("one");
two.someOtherMethod("two");
three.someOtherMethod("three");
four.someOtherMethod("four");
}
}
继承并不是重用公共功能的唯一方法。在一般情况下,最好采用安全壳。 考虑下面的解决方案,其中类A和B是单独的,并且共同的功能在类AB中,但不是扩展AB,A和B都使用AB,这是一个单独的实例。
class AB { //common functionality of A and B
//singleton pattern here
//common data and functionality here
}
class A {
private AB ab = AB.getInstance();
//singleton pattern here
//unique functionality and data of A
//to use any of the functionality in AB delegate to member ab
}
B类与A类相似
在此解决方案中,a和B(以及AB)的每个数据和功能都有一个实例
注意,如果A和B的客户端需要访问AB中的公共方法,那么
AB、A和B应该实现这些公共方法的接口,A和B实现应该将调用委托给AB
下面由欧内斯特提出的解决方案在某些情况下可能是一种捷径,但通常是错误的解决方案 为了解释为什么欧内斯特的解决方案可能是错误的,让我们用另一种方式来描述该解决方案。 假设我有一个单例类a,我发现我需要编写另一个单例类B,但我需要B中a的一些功能。因此我将a的公共数据和功能分解成一个抽象类AB,并使a和B都扩展AB。 一般来说,这是错误的,因为此解决方案将数据和功能的一个子集(假定只存在一次)放在子类(AB)中,有效且潜在地在将创建的每个子类中复制它。现在,在获得A的一个实例和B的一个实例之后,在AB中有两个子集数据和功能的实例 例如,如果基类中的公共功能将一些初始数据写入名为“myData”的文件,那么您的两个单例都将执行此代码,即使它只执行一次,并且当后者执行时,它将清除前者创建的文件
因此,一般来说,这里描述的解决方案不使用继承,并确保单例封装公共功能以及使用它的单例类。我有一个类似的要求:我有多个缓存映射,其中包含重复的方法和成员,因此我创建了一个抽象类,如:
public abstract class AbstractCache<T> {
protected final Map<String, T> cache;
protected AbstractCache() {
this.cache = getDefaultExpiringMap(TimeUnit.HOURS.toMillis(4));
}
public Map<String, T> getCache() {
return cache;
}
public T getAll(String id) {
return cache.get(id);
}
}
我认为这并不像塔特那么容易。是的,尝试将“单音化”作为抽象实现是一个愚蠢的想法——它不起作用。不过,正如我所说的,两个碰巧共享一个基类的类都单独实现为singletons.hhmmm不会有任何问题,我们将尝试这个方法。人们在谈论接口和工厂模式,我真的confused@sura这是一种观点(只要我不争辩,我可以),但c2.com维基已经变得毫无用处。我认为这和姐妹的地方是下一代的C2.com,这就是为什么我在这里逗留,很少访问那里。“单身作为抽象”是控制框架倒置的优势之一。主要用例是在从开发、测试、部署平台或部署到不同平台时能够轻松更改组件的实现。单例是软件的不朽之物。假设只有一个,但我们仍然用刀剑、斧头和斧头来破解代码,以确保实现……你不能这样做,因为单例有一个私有构造函数。@苏拉:你可以使用“受保护”的访问修饰符而不是私有修饰符来隐藏构造函数。这样,只有子类可以调用它,但外部世界仍然不能调用它
public final class FooCache extends AbstractCache<Set<Integer>> {
public static final FooCache INSTANCE = new FooCache();
private FooCache() {
super();
}
public void add(String fooId, Integer value) {
cache.computeIfAbsent(fooId, k -> new HashSet<>()).add(value);
}
}
public static void main(String[] args) {
FooCache.INSTANCE.add("a", 1);
System.out.println(FooCache.INSTANCE.getAll("a"));
}