首页 >> 中医诊断

设计模式之单态模式计划

中医诊断  2021年09月06日  浏览:2 次

我们看到的是一个简单的类图表,显示有一个 Singleton 对象的私有静态属性以及返回此相同属性的公共方法 Instance()。 这实际上是 Singleton 的核心。 还有其他一些属性和方法,用于说明在该类上允许执行的其他操作。 为了便于此次讨论,让我们将重点放在实例属性和方法上。

客户端仅通过实例方法来访问任何 Singleton 实例。 此处没有定义创建实例的方式。 我们还希望能够控制如何以及何时创建实例。 在 OO 开发中,通常可以在类的构造函数中最好地处理特殊对象的创建行为。 这种情况也不例外。 我们可以做的是,定义我们何时以及如何构造类实例,然后禁止任何客户端直接调用该构造函数。 这是在 Singleton 构造中始终使用的方法。 让我们看一下 Design Patterns 中的原始示例。 通常,将下面所示的 C++ Singleton 示例实现代码示例视为 Singleton 的默认实现。 本示例已移植到很多其他编程语言中,通常它在任何地方的形式与此几乎相同。

C++ Singleton 示例实现代码

// Declaration

class Singleton {

public: static Singleton* Instance();

protected: Singleton();

private: static Singleton* _instance;

}

// Implementation

Singleton* Singleton::_instance = 0;

Singleton* Singleton::Instance() {

if (_instance == 0) {

_instance = new Singleton;

}

return _instance;

}

让我们先花点时间分析一下此代码。 该简单类有一个成员变量,此变量是指向该类自身的指针。 注意,构造函数是受保护的,并且只有公共方法才是实例方法。 在实例方法实现中,有一个控制块 (if),它检查成员变量是否已初始化,如果没有的话,则创建一个新实例。 控制块中这种惰性初始化意味着仅在第一次调用 Instance() 方法时初始化或创建 Singleton 实例。 对于很多应用程序,这种方法效果很好。 但对于多线程应用程序,这种方法证明具有潜在危险的副作用。 如果两个线程同时进入控制块,则可能会创建该成员变量的两个实例。 要解决这一问题,您可能想只将重要部分放在控制块周围以确保线程安全。 如果您这样做,则将对实例方法的所有调用进行序列化处理,并且可能会对性能产生不利影响(取决于应用程序)。 正是由于这个原因,创建了此模式的另一个版本,它使用某种称为双重检验机制的功能。 下一个代码示例显示使用 Java 语法的双重检验锁定。

使用 Java 语法的双重检验锁定 Singleton 代码

// C++ port to Java

class Singleton {

public static Singleton Instance() {

if (_instance == null) {

synchronized (rName(\"Singleton\")) {

if (_instance == null) {

_instance = new Singleton();

}

}

}

return _instance;

}

以及随之而来的40次对11次的罚球差异。公牛队全场失误达16次之多 protected Singleton() {

}

private static Singleton _instance = null;

}

在使用 Java 语法的双重检验锁定 Singleton 代码示例中,我们直接将 C++ 代码移植到 Java 代码,以便利用 Java 关键部分块(已同步)。 主要差别是不再有单独的声明和实现部分,没有指针数据类型,并且采用了新的双重检验机制。 双重检验发生在第一个 IF 块上。 如果成员变量为空,则执行进入关键部分块,该块再次双重检验该成员变量。 仅在通过此最终测试后,才会实例化该成员变量。 一般来说,两个线程无法使用这种方法创建两个类实例。 另外,因为在第一次检查时没有出现线程阻塞,所以对此方法的大多数调用不会由于必须进入锁定而导致性能下降。 目前,在实现 Singleton 模式时,很多 Java 应用程序中都广泛使用这种方法。 这种方法很巧妙,但也有瑕疵。 某些优化编译器可以将惰性初始化代码优化掉或对其重新进行排序,并且会重新产生线程安全问题。 有关更深入的解释,请参阅 \"The Double-Check Locking is Broken\" Declaration。

另一种试图解决此问题的方法可能是,在成员变量声明中使用 volatile 关键字。 这应该告诉编译器不要对代码重新排序,并且放弃优化。 目前,这是唯一建议的 JVM 内存模型,并且不会立即解决该问题。

实现 Singleton 的最好方法是什么? 最终(而不是碰巧),Microsoft .NET 框架解决了所有这些问题,从而更易于实现 Singleton,却不会产生我们目前讨论的不利副作用。 .NET 框架以及 C# 语言允许我们在必要时通过替换语言关键字,将上述的 Java 语法移植到 C# 语法。 因此,Singleton 代码变为以下内容:

以 C# 编码的双重检验锁定

// Port to C#

class Singleton {

public static Singleton Instance() {

if (_instance == null) {

lock (typeof(Singleton)) {

if (_instance == null) {

_instance = new Singleton();

}

}

}

return _instance;

}

protected Singleton() {

}

private static volatile Singleton _instance = null;

}

西安最好的人流医院
郑州包皮过长哪家好
容易疲劳嗜睡是什么原因
友情链接