Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 领域驱动设计-单例_C#_Design Patterns_Singleton_Domain Driven Design - Fatal编程技术网

C# 领域驱动设计-单例

C# 领域驱动设计-单例,c#,design-patterns,singleton,domain-driven-design,C#,Design Patterns,Singleton,Domain Driven Design,当我们使用ddd时,创建一个单例是个坏主意 我正在考虑创建两个,一个用于全局设置(保存在数据库中),另一个用于本地设置(保存在应用程序Windows窗体的Windows注册表中) 如果ddd中的单例是可以接受的,我应该在何时何地用存储值填充它们?根据您的情况,按原样(1)实现的单例在ddd中是不可接受的(2)甚至在任何其他现代软件开发范例中也是如此。请注意,DDD不仅仅是一种软件架构范例,但当我说普通的单例实现是不可接受的时,我指的是如何在C#等编程语言中正确实现DDD 例如,以下代码示例可能是

当我们使用ddd时,创建一个单例是个坏主意

我正在考虑创建两个,一个用于全局设置(保存在数据库中),另一个用于本地设置(保存在应用程序Windows窗体的Windows注册表中)

如果ddd中的单例是可以接受的,我应该在何时何地用存储值填充它们?

根据您的情况,按原样(1)实现的单例在ddd中是不可接受的(2)甚至在任何其他现代软件开发范例中也是如此。请注意,DDD不仅仅是一种软件架构范例,但当我说普通的单例实现是不可接受的时,我指的是如何在C#等编程语言中正确实现DDD

例如,以下代码示例可能是singleton的简单实现:

它们是不可交换的,这意味着您不能使用依赖项注入(3)来注入它们。也就是说,测试也更难实现(您应该理解,无法测试或难以测试的系统是一个非常糟糕的想法)

可以接受的是使用依赖项注入/控制反转容器,该容器可以定义组件实现的生活方式,如Castle Windsor和其他,这意味着您仍然可以使用依赖项注入,并定义在应用程序的生命周期中只创建一个实例(也就是说,您得到了一个实例,其中您得到了一个注入的组件实现,但一旦内部组件工厂创建了一个,这就是在一个应用程序生命周期中注入的组件实现)

归根结底,您的系统被设计为不知道组件生命周期如何工作。它是由配置定义的。我想说,当您的系统以这种方式设计时,对象生命周期管理是一个方面()

将组件生命周期管理委托给一个方面并定义组件的生命周期是一个巨大的优势:您的代码可以在许多托管环境中工作,并且在每个托管环境中,您的代码可以根据配置的不同而工作

想想ASP.NET WebAPI。在单个请求期间,可能有些组件应该是单例的,每个请求都应该使用自己的单例。在另一个环境中使用的相同组件可能不应该是单例的,而只是一个临时对象(即,每次注入它时,它都是一个全新的对象).使用普通的单例实现,您将无法获得这种灵活性

你的要求做得对 有许多可能的方法可以很好地解决您的问题。我将介绍其中两种可能的解决方案:

1.不要考虑全局设置对象,而应将这些设置作为一类设置注入到需要这些设置的每个组件中 例如:

public interface IDatabaseSettings 
{
     string Host { get; set; }
}

public class RegistryDatabaseSettings : IDatabaseSettings
{
     // This property should get and set the setting from and
     // against the Windows Registry. It's just a sample and dummy
     // implementation
     public string Host { get; set; }
}

public interface ISomeRepository
{
}

public class SomeRepositoryImpl : ISomeRepository
{
    private readonly IDatabaseSettings _dbSettings;

    // Inject IDatabaseSetttings as constructor's dependency
    public SomeRepositoryImpl(IDatabaseSettings dbSettings)
    {
         _dbSettings = dbSettings;
    }

    public IDatabaseSettings DatabaseSettings => _dbSettings;
}
使用您最喜欢的控制反转/依赖注入容器,您可以定义
IDatabaseSettings
必须在每个应用程序周期实例化一次(即单例)

2.如果设置是跨层问题。。。 …也许您可以定义一个名为
Settings
的类,在该类中,您将所有设置定义为公共属性,并将单例实例注入任何需要它的组件中:

public interface IDatabaseSettings
{
     string Host { get; set; }
}

public interface ISettings 
{ 
     IDatabaseSettings Database { get; }
}

public interface ISomeRepository
{
}

public class SomeRepositoryImpl : ISomeRepository
{
    private readonly ISettings _settings;

    // Inject Settings as constructor's dependency
    public SomeRepositoryImpl(ISettings settings)
    {
         _settings = settings;

         // Now you can access DatabaseSettings as follows:
         // Settings.Database.Host
    }

    public ISettings Settings => _settings;
}
对我来说,这种方法的问题是你要将设置注入到不应该访问/写入来自其他域的设置的组件中,或者它们不希望在任何地方都被访问。我要说的是不要打破面向对象编程中最重要的原则之一:封装

(1) 当我谈论单例模式实现时,我正在描述一个普通的单例模式实现,其中整个单例类实现单对象生命实例化/管理

(二)OP讨论了应该存储在某些数据库和Windows注册表中的设置。不使用依赖项注入是一个坏主意,因为如果不涉及数据库和Windows注册表,就没有机会对需要整个设置的组件进行单元测试。不可能设置伪设置。

(三)一些控制反转容器支持使用自定义工厂配置组件,在自定义工厂中,您可以定义可以从任何自定义源获取某个实现的实例。例如,该工厂可以返回
SomeSingleton.instance
,并将其作为任何常规组件注入。

作为i实现的Singleton根据您的案例,在DDD中,s(1)是不可接受的(2),甚至在任何其他现代软件开发范式中也是不可接受的。请注意,DDD不仅仅是一种软件体系结构范式,但当我说普通的单例实现是不可接受的时,我指的是如何在像C#这样的编程语言中正确地实现DDD

例如,以下代码示例可能是singleton的简单实现:

它们是不可交换的,这意味着您不能使用依赖项注入(3)来注入它们。也就是说,测试也更难实现(您应该理解,无法测试或难以测试的系统是一个非常糟糕的主意)

可以接受的是使用依赖项注入/控制反转容器,该容器可以定义组件实现的生活方式,如Castle Windsor和其他,这意味着您仍然可以使用依赖项注入,并定义在应用程序的生命周期中只创建一个实例(也就是说,您得到了一个实例,其中您得到了一个注入的组件实现,但一旦内部组件工厂创建了一个,这就是在一个应用程序生命周期中注入的组件实现)

归根结底,您的系统被设计成不知道组件生命周期是如何工作的。它是由配置定义的。我想说的是,对象生命周期管理
public interface IDatabaseSettings
{
     string Host { get; set; }
}

public interface ISettings 
{ 
     IDatabaseSettings Database { get; }
}

public interface ISomeRepository
{
}

public class SomeRepositoryImpl : ISomeRepository
{
    private readonly ISettings _settings;

    // Inject Settings as constructor's dependency
    public SomeRepositoryImpl(ISettings settings)
    {
         _settings = settings;

         // Now you can access DatabaseSettings as follows:
         // Settings.Database.Host
    }

    public ISettings Settings => _settings;
}