MEF对单例模式有什么价值吗?

5
我正在开发一个MEF项目,以了解其使用和实现技巧。我探索的第一阶段是实现一个动态可配置且集中式的数据控制器。自定义行为的一种方法是继承我提供的强制执行单例规则的类。虽然单例模式在使用中经常受到诟病,但我可能已经找到了一种可以在一定程度上验证该模式困难存在的实现方式。
情况:
假设主机导入的数据控制模块(DataController)旨在按请求向同级模块提供与数据库的公共通道。我只需要一个DataController,并且要作为模块组成,DataController必须实现IDataController接口。将DataProvider实现为基类是完全可选的;但是,从DataProvider派生将需要一些额外的处理。
观察:
收集事实:
- 静态类无法实现或扩展抽象类或接口。仅此事实就排除了使用静态类来确保DataController的唯一存在性。 - 实现Singleton模式的DataController将确保每个应用程序域内的唯一存在。 DataController没有任何限制;允许继承所需接口以被导入并在主机中组合。 - 给定DataController的派生,标准Singleton模式的实现在某些情况下可能会证明是具有挑战性的。所提供的数据库同时提供了可公开访问的类:IDataController和抽象DataProvider。为确保派生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。
话虽如此,我很好奇是否有比我设计的更可接受或实用的实现方法。而且,我开始质疑Singleton模式是否是正确的选择。鉴于Singleton模式的存在备受诟病(大多数情况下是有道理的),我应该质疑自己的选择。
我的问题是: - 是否有更实用的实现方法来满足我的要求? - 在这种情况下,这是Singleton模式的正确实现吗? - 这种实现是否真正有助于模式的存在?
2个回答

18

如果你想强制确保容器中只存在一个类的实例,那么你可以将 "shared" 部分的创建策略设置为:

[Export(typeof(IDataController))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class DataController : IDataController
{
    ...
}
每个导入 IDataController 的部分都会接收相同的实例。请注意,如果在导入或导出端未指定任何部分创建策略,则这已经是 MEF 中的默认行为。
您不应将“单例性”构建到类中。无论某物是否为单例都是组件元数据或容器配置的一部分。其他依赖注入容器采用相同的方法。例如,在 autofac 中,您可以像这样声明某些东西是单例:
builder.Register(c => new DataController())
    .As<IDataController>().SingleInstance();

2
这就是第一阶段结束的故事,虽然有些反高潮。完全有道理。这正是为什么“如果你认为 Singleton 是答案,你应该先问问”的好建议。 - IAbstract
单例模式再次无法通过审查。 - IAbstract

0

除非您有更多的实现代码,所有从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();
    }
}

聪明,但考虑到@Wim的答案,这是不必要的。不过,了解微软,如果有一个单例深藏其中,那也不会让我感到惊讶。;) - IAbstract
我完全同意并投票支持他的答案。不过,我决定不删除我的回答,因为它提供了一个“更好”的单例实现。这难道不是个矛盾吗? - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接