【问题标题】:How can I make a family of singletons?我怎样才能建立一个单身家庭?
【发布时间】:2010-05-03 13:47:38
【问题描述】:

我想创建一组具有许多共同行为的类。当然,在 OOP 中,当您认为您会自动想到“带有子类的抽象类”时。但是我希望这些类做的事情之一是每个类都有一个静态的类实例列表。该列表应该作为类中的单例。我的意思是每个子类都有一个单例,而不是它们共享一个。该子类的“单例”,而不是真正的单例。但是如果是静态的,我怎么继承呢?

当然这样的代码是行不通的:

public abstract A
{
  static List<A> myList;
  public static List getList()
  {
    if (myList==null)
      myList=new ArrayList<A>(10);
    return myList;
  }
  public static A getSomethingFromList()
  {
    List listInstance=getList();
    ... do stuff with list ...
  }
  public int getSomethingFromA()
  {
    ... regular code acting against current instance ...
  }
}
public class A1 extends A
{
  ...
}
public class A2 extends A
{
   ...
}

A1 somethingfromA1List=(A1) A1.getSomethingFromList();
A2 somethingfromA2List=(A2) A2.getSomethingFromList();

每个子类的列表内容会有所不同,但在列表上工作的所有代码都是相同的。

上述代码的问题在于,我只有一个包含所有子类的列表,并且我想要每个子类一个。是的,我可以复制代码以在每个子类中声明静态列表,但是我还必须复制添加到列表和搜索列表等的所有代码,这反而违背了子类化的目的。

关于如何在不复制代码的情况下做到这一点的任何想法?

更新

为了向 BlueRaja 和其他人澄清,让我更具体地说明我正在尝试做什么。

我有许多需要类似行为的状态和代码。它们就像枚举,因为我希望为每种可能的代码状态提供类型安全的实例,但它们有多个集合,所以我不能只为它们创建一个枚举。

例如,我有订单状态,其中包含在订单、已发货、已收到的值和一些特殊值。我有项目类型,具有商品与服务的值。我有库存与定制。等等。

如果这就是它的全部,我会为每一个做一个枚举。但是我还需要其他行为,例如通过文本值查找对象的能力,例如当我们从数据库中读取它时;建立一个下拉列表,通过文本描述列出所有选项;等等。据我所知,我不能用枚举来做到这一点,因为我有几组代码,每组都有我想要继承的共同行为,而且我不能子类化枚举。将所有代码放在一个枚举中会放弃一个代码与另一个代码的类型安全性,并证明没有现成的方法来收集特定代码类型的值列表。

【问题讨论】:

  • 不要在面向对象的世界中使用静态保持状态,这是错误的。
  • 不要使用单例,对静态数据要非常小心。更喜欢组合而不是继承。真的,你提到的几乎没有什么是真正“好的 OOP”。
  • 好的。所以我有一组给定子类的实例,我需要维护所有这些实例的列表,用于搜索、构建下拉列表等。好吧,我可以创建一个包含该列表的(非静态)对象。但只有一个列表才有意义。那么这样做有什么好处呢?如果我创建了两个具有不同列表的对象,那就大错特错了。如果没有单例,你将如何解决问题?

标签: java design-patterns oop singleton


【解决方案1】:

您可以在父类中使用static Map&lt;Class, YourClass&gt; = new ConcurrentHashMap&lt;..&gt;() 并使用该映射来添加/检索实例。

尽管如此依赖单例对我来说听起来像是一个糟糕的设计 - 你应该尽量避免它。

【讨论】:

  • 问题是:子类中的静态变量如何从 HashMap 中提取适当的条目?我看到这样做的唯一方法是将静态保留在超类中并将类名作为参数传递,例如“A1 a1 =(A1)A.getSomethingFromA(A1.class)”。可以,但有点尴尬。你有更简单的方法吗?
【解决方案2】:

What is so bad about singletons?

编辑:问题回复后: 您说“我想创建一组具有许多共同行为的类”——对我来说,这并不意味着“带有子类的抽象类”,因为抽象类没有任何行为。它建议使用一个单独的对象来实现常见行为,以及许多聚合该单独对象的类。

【讨论】:

  • 好的。那么如果没有单例,你将如何解决这个问题呢?
  • 您说“我想创建一组具有许多共同行为的类”——对我来说,not 是否建议“带有子类的抽象类” ",因为抽象类没有行为。它建议使用一个单独的对象来实现常见行为,以及许多聚合该单独对象的类。
【解决方案3】:

听上去,你真正想要的是一个具有自定义属性和behaviours 的枚举类。请参阅here,了解 Java 中枚举的强大功能的示例。

【讨论】:

  • 是的,我想要的确实是一个复杂的枚举。但我想要几十个具有相同细节的课程。据我所知,我不能对枚举进行子类化。所以是的,我可以通过使用相同的代码制作一大堆枚举来实现这一点。但是复制和粘贴代码是维护的噩梦。除非有一种方法可以对枚举进行子类化,否则我不会在这里削减它。
  • @Jay:不,你想要一个 single 枚举类,不涉及子类化。您现在使用的每一件事实际上都是一个枚举值。每个“类”的自定义行为实际上是抽象枚举方法的实现,特定于每个枚举值。与任何其他类一样,共享的所有内容都只是枚举的一部分。不会涉及复制/粘贴 - 您所描述的情况正是 Java 强大的枚举的用途。
  • 我认为你误解了我的要求。 (或者我误解了你。)我正在更新原始问题以更具体,也许这会澄清。
【解决方案4】:

我会考虑工厂方法:

public class Factory {
  private static final A1 a1Instance = new A1(
          Collections.synchronizedList(new ArrayList<something>(100)));
  private static final A2 a2Instance = new A2(
          Collections.synchronizedList(new ArrayList<something>(100)));

  public static A getA1() { return a1Instance; }
  public static A getA2() { return a2Instance; }
}

当然,您的 A 不再需要所有这些 static 方法了。

【讨论】:

    【解决方案5】:

    你可以使用类的索引,静态列表不需要你可以只使用引用这些cors类和子类的实例的索引。 这是一个例子: http://www.java2s.com/Code/CSharp/Class-Interface/Indexerallowarraylikeindex.htm

    【讨论】:

      【解决方案6】:

      如果您需要单例功能,同时又想从继承中受益,您应该考虑依赖注入框架,例如 SpringPicoContainer。即使您的应用程序非常小,使用管理依赖项的框架仍然会更轻松。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-01
        • 1970-01-01
        • 2013-01-08
        相关资源
        最近更新 更多