Monostate vs. Singleton

时间:2009-05-20 11:04:24

标签: design-patterns language-agnostic singleton

为了维护全局对象,使用Monostate模式而不是singleton的情况是什么?

编辑: 我知道Singleton和Monostate模式是什么。在很多场景中也实现了Singleton。只想了解需要实现MonoState模式的场景(案例)。

例如。我需要在我的Windows窗体应用程序中维护每个屏幕的列列表。在这种情况下,我可以使用Singleton Dictionary。但是,我在静态全局var中存储了一个List,我想提供索引器(因为我需要动态地将新条目添加到列表中,如果key不存在),我可以将ScreenDetails.ScreenName指定为键和&获取ScreenDetails.ColumnsTable。由于索引器无法在静态类上操作,因此我将模式更改为Monostate。

所以我想知道哪些其他场景可能迫使用户使用Monostate而不是Singletons。

5 个答案:

答案 0 :(得分:67)

monostate和singleton是同一枚牌的两面(全局状态):

  • monostate强制行为(所有类实例中只有一个值)
  • singleton强制结构约束(仅一个实例)

单身使用不透明

即:

Singleton singleton = Singleton.getInstance();

monostate用法是透明的

即:

MonoState m1 = new MonoState();
MonoState m2 = new MonoState(); // same state of m1 

答案 1 :(得分:41)

以下是 Robert C. Martin 对此所说的话:Singleton vs. Monostate (pdf)

  

当你有一个想要约束的现有类时,最好使用SINGLETON   通过派生,你不介意每个人都必须调用实例()   获取访问权限的方法。 Monostate最适合用于你想要的单一性质   class对用户透明,或者当你想使用多态衍生物时   单个对象。

答案 2 :(得分:17)

在它的基础Monostate只是Singleton周围的语法糖。 Monostate变得有趣的地方是你开始子类化时,因为子类可以用不同的行为来装饰共享状态。

一个简单的 - 如果有点做作,效率不高:) - 例如:

public class GlobalTable implements Iterable<Key> {

  /** Shared state -- private */    
  private static final Map<Key, Value> MAP = new LinkedHashMap<Key, Value>();

  /** Public final accessor */    
  public final Value get(Key key) {
    return MAP.get(key);
  }

  /** Public final accessor */    
  public final boolean put(Key key, Value value) {
    return MAP.put(key);
  }

  /** Protected final accessor -- subclasses can use this to access
      the internal shared state */    
  protected final Set<Key> keySet() {
    return MAP.keySet();
  }

  /** Virtual -- subclasses can override for different behavior */    
  public Iterator<Key> iterator() {
    return Collections.unmodifiableSet(MAP.keySet()).iterator();
  }
}

现在如果我们想要索引访问怎么办?

public class IndexedGlobalTable extends GlobalTable {

  public List<Key> getKeysAsList() {
    return Collections.unmodifiableList(new ArrayList<Key>(keySet()));
  }

  public Key getKeyAt(int index) {
    return getKeysAsList().get(index);
  }

  public Value getValueAt(int index) {
    return get(getKeyAt(index));
  }
}

排序键怎么样?

public class SortedGlobalTable extends GlobalTable {

  @Override
  public Iterator <Key> iterator() {
    return Collections
      .unmodifiableSortedSet(new TreeSet<Key>(keySet())).iterator();
  }

}

只要您需要一个或另一个数据视图,就可以实例化相应的子类。

当然,首先,全球数据是否真的是一个好主意是另一个问题,但至少Monostate为您提供了更灵活的使用方式。

答案 3 :(得分:8)

有人应该注意单身人士和单身人士是非常危险的模式。他们倾向于被懒惰的程序员误用,他们不想考虑他们想要成为单身人士的对象的生命周期。它们使测试更加困难,并创建了紧密绑定的不灵活系统。

找到真正需要单身人士或单人身份的情况极为罕见。对象协作的首选方法是依赖注入。

有很多人写过:

答案 4 :(得分:1)

两种模式之间的区别在于行为与结构之间的区别。 SINGLETON 模式强制执行奇点结构。它可以防止创建任何多个实例。而 MONOSTATE 强制执行奇点行为而不强加结构约束。

SINGLETON的好处

  • 适用于任何课程。您可以将任何类更改为SINGLETON 只需将其构造函数设为私有,并添加适当的静态函数和变量。
  • 可以通过派生来创建。给定一个类,你可以创建一个 子类是SINGLETON。
  • 懒惰的评价。如果从未使用SINGLETON,则永远不会创建它。

SINGLETON的费用

  • 销毁未定义。没有好的方法来摧毁或 退役一个SINGLETON。如果添加一个使实例为空的decommission方法,则系统中的其他模块可能仍然持有a 引用SINGLETON实例。对Instance的后续调用将导致创建另一个实例,从而导致存在两个并发实例。

  • 不继承。从SINGLETON派生的类不是单例。 如果它需要是SINGLETON,静态函数和变量需要 加入它。

  • 效率。每次调用Instance都会调用if语句。对于大多数 在那些电话中,if语句没用。

  • 非透明。 SINGLETON的用户知道他们正在使用 SINGLETON因为他们必须调用Instance方法。

MONOSTATE的好处

  • 透明度。 MONOSTATE的用户行为不同于 常规对象的用户。用户不需要知道 对象是MONOSTATE。

  • 导性。 MONOSTATE的衍生物是MONOSTATES。确实,所有 MONOSTATE的衍生物是同一个MONOSTATE的一部分。他们 所有人都拥有相同的静态变量。

  • 多态性。由于MONOSTATE的方法不是静态的,所以它们 可以在衍生物中覆盖。因此不同的衍生物可以 在同一组静态变量上提供不同的行为。

  • 明确定义的创建和破坏。 MONOSTATE的变量, 是静态的,具有明确定义的创建和破坏时间。

MONOSTATE的费用

  • 无转换。普通类无法转换为MONOSTATE 通过推导来分类。

  • 效率。 MONOSTATE可以经历许多创作和 破坏,因为它是一个真实的对象。这些操作经常是 昂贵的。

  • 存在。 MONOSTATE的变量占用空间,即使是 从未使用过MONOSTATE。

敏捷软件开发,原则,模式和实践Robert C. Martin