Drago
Drago

Reputation: 1875

Abstract class singleton C#

public sealed class HomePage : Page
{
    public override void GoTo()
    {
        throw new System.NotImplementedException();
    }

    public override void IsAt() => Assert.IsTrue(Browsers.Title.Equals("home"));
}

I have bunch of page object classes like HomePage which I want to turn into a singleton.

I was looking at Jon Skeet's site on implementing the Singleton pattern.

An example of how to implement the Singleton pattern as per the site mentioned above:

public sealed class Singleton {
 private static readonly Singleton instance = new Singleton();

 static Singleton() {}

 private Singleton() {}

 public static Singleton Instance {
  get {
   return instance;
  }
 }
}

I want to implement this for all my page objects. All my page objects inherit from an abstract base class Page.

public abstract class Page 
{
    private static readonly Page instance = new Page();

    public abstract void IsAt();

    public abstract void GoTo();
}

I'm trying to implement the Singleton pattern I mentioned earlier on my Page base class. But the problem is my Page class is abstract and I can't do the following:

private static readonly Page instance = new Page(); // Since Page is abstract I can't do this.

How can I implement the singleton pattern without having to implement it for each child class individualy?

Upvotes: 1

Views: 414

Answers (2)

canton7
canton7

Reputation: 42225

Your question is specifically about being able to implement the singleton pattern solely using the base class, without making any code changes to the derived classes.

It's possible to do something like this:

public abstract class Page
{
    // Your normal Page base class things
}

public abstract class Page<T> : Page where T : Page<T>, new()
{
    // Or whatever singleton pattern you want to implement
    public static readonly T Instance = new T();
}

public class HomePage : Page<HomePage>
{
}

This lets you write:

var homePage = HomePage.Instance;

This works because Page<T> has its own set of static data which is separate for each T - so Page<HomePage> has separate static data to Page<LogInPage>.

You will however need to modify each of your pages to derive from Page<PageSubclass>, rather than from Page.


That said, I would take the simpler route of adding code like:

public static readonly HomePage Instance = new HomePage();

to each of your Page subclasses. This is significantly less "magic", doesn't rely on reflection to instantiate the pages, and will only take you a few minutes to add to even 70 page objects. After all, you'll have to modify them all to derive from Page<T> to use this pattern anyway.

Upvotes: 3

mikelegg
mikelegg

Reputation: 1327

You can kind of do this, but just because you can do something, it does not mean it is a good idea. Think if it really makes the code easier to understand or not. Sometimes the amount of abstraction makes it just not worth it

    public abstract class Page<T> where T: new()
{
    public static readonly T instance = new T();

    public abstract void GoTo();
}


public class Home : Page<Home>
{
    public override void GoTo()
    {
        Console.WriteLine("goto home");
    }
}

public class Login : Page<Login>
{
    public override void GoTo()
    {
        Console.WriteLine("goto Login");
    }
}

Then:

        Home.instance.GoTo();
        Login.instance.GoTo();

The thing is it is not a nice pattern. You might be better doing something like this so you avoid singletons:

pages["Home"].Goto();

Upvotes: 1

Related Questions