Monostate vs. Singleton

Ras*_*dit 45 language-agnostic singleton design-patterns

当人们使用Monostate模式而不是singleton来维护全局对象时,会出现什么情况?

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

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

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

dfa*_*dfa 68

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

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

单身使用不透明

即:

Singleton singleton = Singleton.getInstance();
Run Code Online (Sandbox Code Playgroud)

monostate用法是透明的

即:

MonoState m1 = new MonoState();
MonoState m2 = new MonoState(); // same state of m1 
Run Code Online (Sandbox Code Playgroud)

  • +1 - 简单明确的定义.好一个. (3认同)
  • +1读完之后,我再也不会写一个单身人士了! (3认同)
  • 单身人士如何不那么透明?如果我不知道 m1 是一个单态,我会像不知道什么是单身一样一无所知。 (2认同)
  • @Don Scott - > monostate对于客户端如何使用monostate是透明的:`monostate的用户的行为与常规对象的用户不同.用户不需要知道该对象是单独的.在signleton模式中,所有客户端都知道它们使用单​​例,因此单例不太透明. (2认同)

ega*_*aga 41

以下是Robert C. Martin对此的评论:Singleton vs. Monostate(pdf)

如果您希望通过派生限制现有类,则最好使用SINGLETON,并且您不介意每个人都必须调用instance()方法来获取访问权限.当您希望类的单一性质对用户透明,或者您希望使用单个对象的多态导数时,最好使用Monostate.

  • 很棒的链接!鲍勃叔叔规则:-) (4认同)

Dav*_*les 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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));
  }
}
Run Code Online (Sandbox Code Playgroud)

排序键怎么样?

public class SortedGlobalTable extends GlobalTable {

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

}
Run Code Online (Sandbox Code Playgroud)

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

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


Ed *_*kes 8

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

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

有很多关于此的文章:

  • -1表示依赖注入 (2认同)
  • 被评为"-1提及依赖注入"的+1 (2认同)