MEF 是否为 Singleton 模式带来任何价值?

发布于 2024-10-08 08:20:26 字数 2457 浏览 4 评论 0原文

我正在开展一个 MEF 项目,以发现使用和实施技术。我的发现的第一阶段是实现一个动态可配置的集中式数据控制器。自定义行为的一种方法是继承我提供的强制执行奇点规则的类。虽然单例模式在使用中饱受诟病,但我可能已经找到了一种实现,可以在某种程度上验证该模式的存在。

情况

假设主机导入的数据控制模块(DataController)旨在根据兄弟模块的请求向数据库提供公共管道。我只需要一个DataController,并且要组成一个模块,DataController必须实现IDataController。将 DataProvider 实现为基类完全是可选的;但是,从 DataProvider 派生将需要一些额外的处理。

观察

收集事实

  • 静态类不能实现或 扩展抽象类或 接口。仅凭这个事实 消除了静态类的使用 确保一个单一的存在 DataController。

  • 数据控制器实现 单例模式将确保 每个应用程序单一存在 领域。没有限制 数据控制器;允许继承 需要导入的接口以及 在主机中组成。

  • 给定 DataController 的派生, 标准实施 单例模式可能被证明是 在相同的情况下具有挑战性。这 建议的数据库同时提供 公开访问的课程: IDataController 和抽象 数据提供者。为保证单 派生的 DataController 的实例, 实施将需要一些 偏离标准。

解决方案

至此,解决方案似乎很清楚了。通过 DataHandler 基类实现 Singleton 模式。我还没有天真地认为还有其他方法可以做到这一点。但这里是我对如何实现该模式的粗略期望:

// DataLibrary referenced by Host
public interface IDataController
{ 
    IDataController Start();
    DbConnection CreateConnection<TDbConnection>(params string[] args)
        where TDbConnection : DbConnection, IDbConnection;
}

public abstract class DataProvider
{

    // singleton implementation
    private static IDataController dcInstance;

    protected static IDataController Instance
    {
        get{ return dcInstance; }
    }
    // ========================

    abstract IDataController CreateController();

    protected IDataController instanceController<TDataController>()
        where TDataController : IDataController, new()
    {
        return new TDataController ();
    }
}

// references DataLibrary
[Export(typeof(IDataController))]
public class DataController : DataProvider, IDataController
{
    public IDataController Start()
    {
         return CreateController();
    }

    protected override IDataController CreateController()
    {
        return instanceController<DataController>();
    }

    public SqlConnection CreateConnection(params string[] args)
    {
        // instance and return new SqlConnection 
    }
}

请记住,我一直在解决这个问题 - 阅读、理论化 - 但尚未完成实现。当我调试任何问题时,很可能会有一些更新。

显然,只有当 DataController 模块继承抽象基类 DataProvider 时,才会强制执行此实现。因此,如果开发人员选择从 DataProvider 派生 DataController,我们理所当然应该强制执行单一性规则,以避免滥用或误用。

尽管如此,我很好奇是否有比我设计的更容易接受或更实际的实现。而且,我开始质疑单例模式是否是正确的选择。由于单例模式的存在饱受诟病(而且,在大多数情况下,这是理所当然的),因此,我应该质疑我的选择。

是否有更实际的实现来满足我的要求? *在这种情况下,这是单例模式的正确实现吗?* 这个实现实际上对模式的存在有任何价值吗?

I am working on an MEF project to discover usage and implementation techniques. My first phase of discovery is to implement a dynamically configurable and centralized data controller. One way to customize behavior is to inherit a class I provide that enforces a singularity rule. While the Singleton pattern is much maligned in it's use, I may have found an implementation that could validate, to some degree, the pattern's struggling existence.

The Situation

Suppose a data control module (DataController) imported by the Host is intended to supply a common conduit to databases on request by sibling modules. I only need one DataController and to be composed as a module, DataController must implement IDataController. Implementation of DataProvider as the base class is purely optional; however, derivation from DataProvider will require some additional handling.

The Observations

Gathering the facts:

  • A static class cannot implement or
    extend abstract classes or
    interfaces. This fact alone
    eliminates the use of a static class
    to ensure a singular existence of a
    DataController.

  • A DataController implementing the
    Singleton pattern would ensure a
    singular existence per application
    domain. There is no restriction on
    the DataController; allowed to inherit the
    required interface to be imported and
    composed in the Host.

  • Given derivation of DataController, the
    standard implementation for the
    Singleton pattern may prove to be
    challenging in same cases. The
    proposed data library provides both
    publicly accessible classes:
    IDataController, and an abstract
    DataProvider. To ensure a single
    instance of the derived DataController,
    the implementation will require some
    deviation from the norm.

The Solution

At this point, the solution seems clear. Implementation of the Singleton pattern by the DataHandler base class. I am not naive enough to think that there are other ways I could do this. But here is my rough expectations on how to implement the pattern:

// DataLibrary referenced by Host
public interface IDataController
{ 
    IDataController Start();
    DbConnection CreateConnection<TDbConnection>(params string[] args)
        where TDbConnection : DbConnection, IDbConnection;
}

public abstract class DataProvider
{

    // singleton implementation
    private static IDataController dcInstance;

    protected static IDataController Instance
    {
        get{ return dcInstance; }
    }
    // ========================

    abstract IDataController CreateController();

    protected IDataController instanceController<TDataController>()
        where TDataController : IDataController, new()
    {
        return new TDataController ();
    }
}

// references DataLibrary
[Export(typeof(IDataController))]
public class DataController : DataProvider, IDataController
{
    public IDataController Start()
    {
         return CreateController();
    }

    protected override IDataController CreateController()
    {
        return instanceController<DataController>();
    }

    public SqlConnection CreateConnection(params string[] args)
    {
        // instance and return new SqlConnection 
    }
}

Keep in mind that I have been working this out - read, theorizing - and have not completed the implementation. There will most likely be some updates as I debug any issues.

Obviously, this implementation is only enforced if the DataController module inherits the abstract base class, DataProvider. Therefore, it stands to reason that we should enforce a rule of singularity to avoid abuse or misuse if the developer opts to derive a DataController from DataProvider.

All that said, I am curious if there is a more acceptable, or practical implementation than what I have devised. And, I begin to question if the Singleton pattern is the right choice. With the Singleton pattern's much maligned existence (and, for the most part, rightfully so), I should, therefore, question my choice.

Is there a more practical implementation to meet my requirements?
*Is this the right implementation of the Singleton pattern in this case?*
Does this implementation actually lend any value to the pattern's existence?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

左耳近心 2024-10-15 08:20:26

如果你想强制容器中只存在一个类的实例,那么你可以设置“共享”部件创建策略:

[Export(typeof(IDataController))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class DataController : IDataController
{
    ...
}

每个导入 IDataController 的部件将接收相同的实例。请注意,如果您在导入或导出端未指定零件创建策略,则这已经是 MEF 中的默认行为。

您不应该将“单例性”构建到类中。某个东西是否是单例是组件元数据或容器配置的一部分。其他依赖注入容器也遵循相同的方法。例如,在 autofac 中,您将某些内容声明为单例,如下所示:

builder.Register(c => new DataController())
    .As<IDataController>().SingleInstance();

If you want to enforce the fact that only a single instance of a class exists in the container, then you can just set the "shared" part creation policy:

[Export(typeof(IDataController))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class DataController : IDataController
{
    ...
}

Each part importing IDataController will then receive the same instance. Note that this already the default behavior in MEF if you specify no part creation policy at the import or export side.

You should not build "singletonness" into a class. Whether something is a singleton is part of the component metadata or the configuration of the container. Other dependency injection containers follow the same approach. For example, in autofac you declare something as being a singleton like this:

builder.Register(c => new DataController())
    .As<IDataController>().SingleInstance();
不知所踪 2024-10-15 08:20:26

除非您有更多来自 DataProvider 的所有派生类共享的实现代码,否则您可能只想删除抽象类。此实现保证线程安全并使用惰性构造而不使用锁。但是,需要 .NET 4。

public interface IDataController
{
    DbConnection CreateConnection<TDbConnection>(params string[] args)
        where TDbConnection : DbConnection, IDbConnection;
}

[Export(typeof(IDataController))]
public class DataController : IDataController
{
    // singleton implementation
    private static volatile Lazy<IDataController> _ControllerInstance = new Lazy<IDataController>(() => new DataController());

    public static IDataController ControllerInstance
    {
        get { return _ControllerInstance.Value; }
    }

    public DbConnection CreateConnection<TDbConnection>(params string[] args) 
        where TDbConnection : DbConnection, IDbConnection
    {
        throw new NotImplementedException();
    }
}

Unless you have more implementation code that all derived classes from DataProvider would share, you might want to simply do away with your abstract class. This implementation guarantees thread-safey and uses lazy construction without the use of locks. However, requires .NET 4.

public interface IDataController
{
    DbConnection CreateConnection<TDbConnection>(params string[] args)
        where TDbConnection : DbConnection, IDbConnection;
}

[Export(typeof(IDataController))]
public class DataController : IDataController
{
    // singleton implementation
    private static volatile Lazy<IDataController> _ControllerInstance = new Lazy<IDataController>(() => new DataController());

    public static IDataController ControllerInstance
    {
        get { return _ControllerInstance.Value; }
    }

    public DbConnection CreateConnection<TDbConnection>(params string[] args) 
        where TDbConnection : DbConnection, IDbConnection
    {
        throw new NotImplementedException();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文