Reputation: 2724
It's a bad idea to create a singleton when we are using ddd?
I'm thinking of creating two of them, one for global settings (which are saved in the database) and the other for local settings (which are saved in the Windows Registry in my application windows forms).
If singletons in ddd is acceptable, where and when should I fill them with the stored values?
Upvotes: 2
Views: 1945
Reputation: 64943
Singletons implemented as is (1) aren't acceptable in DDD based on your case(2) and even in any other modern software development paradigm. Note that DDD is more than a software architectural paradigm, but when I say that common singleton implementation isn't acceptable I'm talking about how to properly implement DDD in programming languages like C#.
For example, the following code sample is a possible simple implementation of singleton:
// Very simple singleton using a static field initializer
public class SimpleSingleton
{
private readonly static SimpleSingleton _instance = new SimpleSingleton();
public SimpleSingleton Instance => _instance;
}
They're not swappable, and this means that you can't inject them using dependency injection(3). That is, testing is harder to implement too (you should understand that a system that can't be tested or it's hard to test is a very bad idea).
What can be acceptable is using a dependency injection/inversion of control container that can define component implementations' life-style like Castle Windsor and others, which means that you can still use dependency injection and define that only a single instance will be created during the life of the application (i.e. you get an instance where you get an injected component implementation, but once one is created by the internal component factory, this is the one that's being injected during one application life-cycle).
At the end of the day, your system is designed to be agnostic about how component life-cycle works. It's defined by configuration. I would say that object life management is an aspect when your system is designed this way (see this Wikipedia article to learn more about aspect-oriented programming).
Delegating component life management to an aspect and define what kind of life will have your components is a great advantage: your code can work in many hosting environments and on each of them your code can work differently by configuration.
Think about an ASP.NET WebAPI. Maybe some components should be singletons during a single request, and each request should work with its own singleton. Same component used in another environment maybe shouldn't be a singleton, but just a transient object (i.e. each time you inject it, it's a completely new object). With common singleton implementations you won't get this flexibility.
There're many possible approaches to provide a good solution to your problem. I'll describe two of many possible solutions:
For example:
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;
}
And using your favourite inversion of control/dependency injection container, you can define that IDatabaseSettings
must be instantiated once per application cycle (i.e. singleton).
...maybe you can define a class called Settings
where you define all settings as public properties and you inject a singleton instance into any component requiring it:
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;
}
For me, the issue with this approach is you're going to inject settings to components that shouldn't access/write settings which are from other domains or they're just not desirable to be accessed everywhere. I'm talking about not breaking one of most important principles in object-oriented programming: encapsulation.
(1) When I talk about a singleton pattern implementation as is, I'm describing a common singleton pattern implementation where the whole singleton class implements the single object life instantiation/management.
(2) OP talks about a settings that should be stored in some database and in Windows Registry. It would be a bad idea not using dependency injection, because there would be no chance to unit test a component requiring the whole settings without also involving the database and Windows Registry. Setting fakes wouldn't be possible.
(3) Some inversion of control containers have support to configure components using custom factories, where you can define that an instance of some implementation can be taken from any custom source. For example, that factory can return SomeSingleton.Instance
and get it injected as any regular component.
Upvotes: 4