Singleton replacement?
In my senario, I have a global setting object, say GlobalSettings, it has a static property "Current" (singleton), and there should be only one GlobalSettings instance.
But...In my data model, there's an entity "L开发者_如何学PythonocalizedContent":
public class LocalizedContent {
public string Title { get; set; }
public string Content { get; set; }
public string CultureName { get; set; }
}
In the constructor, I want to initialize the instance by setting CultureName to default culture of the system, and I can get the default culture name from GlobalSettings.Current.DefaultCultureName.
However, I don't want to use the singleton property "GlobalSettings.Current" in LocalizedContent class, since it will result in strong-coupling. So my question is, where is the right place to set this default culture name?
Thanks in advance!
Why not add a constructor to LocalizedContent
that takes the DefaultCultureName as a parameter?
LocalizedContent can then be re-used without a dependency on GlobalSettings
.
I think the trick here is to add a constructor to the LocalizedContent
class which takes in the values it needs to consume.
public LocalizedContent {
public LocalizedContent(string cultureName) {
this.CultureName = cultureName;
}
}
For convenience sake you could also add a helper method which creates the LocalizedContent
method using the GlobalSettings
values.
public static LocalizedContent CreateLocalizedContent() {
return new LocalizedContent(GlobalSettings.Current.DefaultCultureName);
}
Hm, you may wish to check this out.
In short, what you would like to do is, inject a "culture" source into your localized content object. Consider the following example,
// your public global settings singleton, no big surprises here
// except possibly thread safe locking [shrug] if you are singlethreaded
// you can simplify this model further
public class GlobalSettings
{
// singleton synchronization and instance reference
private static readonly object _instanceSyncRoot = new object ();
private static readonly GlobalSettings _instance = null;
// instance-based synchronization and values
private readonly object _syncRoot = new object ();
private string _cultureName = string.Empty;
// gets public static instance
public static GlobalSettings Current
{
get
{
lock (_instanceSyncRoot)
{
if (_instance == null)
{
_instance = new GlobalSettings ();
}
}
return _instance;
}
}
// gets public culture name
public string CultureName
{
get { lock (_syncRoot) { return _cultureName; } }
set { lock (_syncRoot) { _cultureName = value; } }
}
// private constructor to re-inforce singleton semantics
private GlobalSettings () { }
}
So, a number of things. Typically singletons like this are frowned upon - they are very convenient! but as you point out, lead to tight-coupling between functional components and configuration.
If you would like to move away from this tight coupling, while preserving what exists, you have a few options, easiest being
// define a general-purpose settings interface, i do not much
// care for refactor tools, but you may use re-sharper or built in
// refactor components to "extract" those properties from global
// settings that you need. here we pull out culture name only,
public interface ISettings
{
// gets culture name from underlying settings implementation
string CultureName { get; }
}
public class LocalizedContent
{
public string CultureName { get; set; }
public LocalizedContent (ISettings settings)
{
CultureName = settings.CultureName;
}
}
If you are able to modify GlobalSettings
singleton,
// public singleton is now an implementation of a "loosely coupled
// component" called ISettings
public class GlobalSettings : ISettings { ... }
// elsewhere in code
public LocalizedContent GetLocalizedContent ()
{
LocalizedContent content = new LocalizedContent (GlobalSettings.Instance);
return content;
}
If you are not able to modify GlobalSettings
singleton,
// wrapper class for global settings singleton
public class Settings : ISettings
{
public string CultureName
{
get { return GlobalSettings.Instance.CultureName; }
}
}
// elsewhere in code
public LocalizedContent GetLocalizedContent ()
{
LocalizedContent content = new LocalizedContent (new Settings ());
return content;
}
Now, LocalizedContent
is no longer tightly-coupled to GlobalSettings
singleton. In fact, any implementation of ISettings
will satisfy its constructor dependency.
If your dependencies are as simple as a string or two, this may be overkill. However, if you have other complex components dependent on this global singleton, this approach may be for you :)
精彩评论