Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的单例和继承_Java_Design Patterns_Inheritance_Singleton - Fatal编程技术网

Java中的单例和继承

Java中的单例和继承,java,design-patterns,inheritance,singleton,Java,Design Patterns,Inheritance,Singleton,我有一个基类,它捕获了两个类共有的一些功能。换句话说,我可以创建一个基类,并使这两个类成为该基类的子类。但是,对于这些子类中的每一个子类,可以创建的实例数为1(即,每个子类必须是单例)。 我在谷歌上搜索了一下,发现关于这个问题有一个合理的争论。虽然有几种解决方案,但我不确定它们是否适合我的情况 有谁能告诉我应该如何设计它吗?您可以将每个类单独设置为一个单例,并将基类抽象化。不确定争论的是什么——只是一般来说,单身并不是一个好主意?使用。有一个单独的类,其中包含检索单例的方法,并让它在实例变量或映

我有一个基类,它捕获了两个类共有的一些功能。换句话说,我可以创建一个基类,并使这两个类成为该基类的子类。但是,对于这些子类中的每一个子类,可以创建的实例数为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"));
}