【问题标题】:Does MEF lend any value to the Singleton pattern?MEF 是否为 Singleton 模式提供了任何价值?
【发布时间】:2010-12-19 19:07:21
【问题描述】:

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

情况

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

观察

收集事实

  • 静态类无法实现或 扩展抽象类或 接口。仅此事实 消除了静态类的使用 确保一个单一的存在 数据控制器。

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

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

解决方案

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

// 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 模式的存在备受诟病(而且,在大多数情况下,这是理所当然的),因此,我应该质疑我的选择。

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

【问题讨论】:

    标签: c# singleton mef


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 这就是第一阶段如何结束的故事,尽管它可能是反高潮。完全有道理。这正是为什么,“如果你认为 Singleton 是答案,你应该先问,” 是个好建议。
    • 再一次,单例模式未能通过审查。
    【解决方案2】:

    除非您有更多从 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 的回答,没有必要。但是,了解 MS,如果某处埋有单身人士,我不会感到惊讶。 ;)
    • 大声笑我完全同意并投票赞成他的回答。决定不删除我的,因为它提供了一个“更好的”单例实现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多