0
\$\begingroup\$

I have the following construct for storing and restoring my applications settings to and from XML.

public interface ISettingsProvider : ICustomXmlSerializableObject
{
    void RestoreDefaultSettings(bool force = false);
}

where I use a wrapper for the XmlSerialization to prevent access from multiple threads at the same time. The interface ICustomXmlSerializableObject is merely

public interface ICustomXmlSerializableObject
{
    string GetSerializedFilePath();
}

I then have an abstract class that all my setting providers inherit from, this is

public abstract class SettingsProviderBase : ISettingsProvider 
{
    public virtual string Extension { get { return ".settings"; } }

    public abstract string GetSerializedFilePath();

    public abstract void RestoreDefaultSettings(bool force = false);
}

Then an example of a setting provider concrete implementation would be

public class ConsoleSettingsProvider : SettingsProviderBase
{
    private static ConsoleSettingsProvider instance = null;

    private ConsoleSettingsProvider() { }

    public static ConsoleSettingsProvider Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new ConsoleSettingsProvider();
                if (File.Exists(instance.GetSerializedFilePath()))
                {
                    ConsoleSettingsProvider o = instance.Deserialize();
                    instance = o ?? instance;
                }
                instance.RestoreDefaultSettings();
            }
            return instance;
        }
    }

    public override void RestoreDefaultSettings(bool force = false)
    {
        if (InterfaceSettings == null || force)
            InterfaceSettings = new InterfaceSettings();
    }

    public override string GetSerializedFilePath()
    {
        // Build the required storage directory.
        string path = Utils.CheckBuildRoamingAppDataDirectory(Constants.Trademark);
        return Path.Combine(path, "Console" + Extension);
    }

    [XmlElement, Browsable(false)]
    public InterfaceSettings InterfaceSettings { get; set; }
}

[Serializable]
public class InterfaceSettings : ISettings
{
    private Font font;

    public InterfaceSettings()
    {
        Font = new Font("Consolas", 9.0f);
    }

    public Font Font
    {
        get { return font; }
        set { font = value; }
    }
}

Where ISettings is a marker interface that may allow me to do something later.

My question is concerning the refactoring of this class hierarchy. It would be nice to move the instantiation of these ISettingsProvider types into the abstract class and save some code as the instantiation method is the same for each derived class. Perhaps moving the property to a method and changing the SettingProviderBase class to

public abstract class SettingsProviderBase : ISettingsProvider 
{
    public static virtual T instance = null; 

    public static virtual T Instance<T>() where T : ISettingsProvider 
    {
        if (instance == null)
        {
            instance = new T();
            if (File.Exists(instance.GetSerializedFilePath()))
            {
                T o = instance.Deserialize();
                instance = o ?? instance;
            }
            instance.RestoreDefaultSettings();
        }
        return instance;
    }

    public virtual string Extension { get { return ".settings"; } }

    public abstract string GetSerializedFilePath();

    public abstract void RestoreDefaultSettings(bool force = false);
}

But this clearly is not possible. Can I achieve what I want and if so, how?

\$\endgroup\$
3
\$\begingroup\$

Personally I've always preferred to have limited number of singletons in a project. Generally there's a good need for them, but how you implement them is another question. For instance I've seen people have a single singleton before with properties that were the objects it needed to have single instances of. Obviously any objects linked in a singleton will only have one if you access them through the singleton. this allows you to have ONE singleton object as a sort of container to hold any objects that need to be singletons. Mind you this is a personal preference, so I will digress.

I think the answer you're looking for is here https://stackoverflow.com/questions/16745629/how-to-abstract-a-singleton-class

It requires both the self-referencing generic typing and the use of the new() constraint.

This is the closest I've ever seen to what you're trying to do. It is not very strictly enforced though because of the need for the new() constraint.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I think the use of singleton here for my setting that are accessed globally is "okay", I hope you agree... Great answer, thanks for your time. \$\endgroup\$ – MoonKnight Jun 8 '16 at 15:20
  • \$\begingroup\$ Hi! Welcome to Code Review. Good job on your first post! \$\endgroup\$ – TheCoffeeCup Jun 8 '16 at 15:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.