Question

I have several classes like Button, Textbox and so on but at instantiation of those object they all need one object reference. The button represents a physical button on the screen but it is not an UI element. Instead it should be used it Selenium to interact with the physical buttons.

    public class Button : Element, IButton
    {
        public Button(IService someService) : base()
        {

        }
    }

somewhere later

var b = new Button(someService)
var b = new Button(someService)
var b = new Button(someService)
var b = new Button(someService)

The problem now is that thoughout the application I need to instantiate this button object several times so I always need to pass the reference inside the constructor. This to mee looks like not so good code. So if anybody has a clue on how to do this better I would be very grateful!

Thanks in advance

Was it helpful?

Solution

I would recommend to start with a very simple improvement: just refactor the button instantiation into a method which you can reuse throughout your code.

   Button CreateButton()
   {
       return new Button(someService);
   }

Of course, one to decide where to put this method, which depends on where it is required. In case it is required inside only one class, one can put the method simply there.

In case the method is required in several different classes in your application, the method could be placed into a factory class, where someService is a member variable of that factory, which is passed through the constructor of the factory:

   class ButtonFactory
   {
       ButtonFactory(someService)
       {
            this.someService = someService;
       }

       Button CreateButton()
       {
           return new Button(someService);
       }
  }

Now you have to initialize the factory once in your application with the correct service, and reuse it throughout the application where it is required.

The code which uses this will then look like

  Button button = buttonFactory.CreateButton();

which is not shorter than the original. But the benefit is that you can now pick the correct service once, in one place of the application, and create the buttons elsewhere. In case you want to pick a different service later, there will be only one place (the factory construction) to be changed in the code.

If text boxes require the same service, you can extend the factory class by adding a similar method CreateTextbox() to it (of course, the factory then should be renamed to something like ElementFactory or ControlFactory).

OTHER TIPS

As an additional idea for improvements, one may consider not to make the general Button class directly dependent from something like a special service.

The button represents an UI element. Maybe one wants to reuse it in different contexts. Tying it to something very application-specific like a business logic service prevents re-use across applications.

Observer Pattern

Let the button do it's stuff and use polymorphism to decouple that from what should happen when the button is interacted with:

(i'll use java syntax here, but you get the point):

interface Runnable {
    void run();
}

class Button {
    private List<Runnable> clickListeners = new List();

    public void addClickListener(Runnable listener) {
        this.clickListeners.add(listener);
    }

    private void onMouseLeftClicked() {
        if (this.disabled) return;

        this.clickListeners.forEach(listener -> listener.run());
    }
}

class MyApplicationWindow extends Window {
    public MyApplicationWindow(Runnable onFormSubmit) {
         // construct all of the UI layout and stuff
         Button submitButton = new Button();

         // here is where you connect UI and business logic:
         submitButton.addClickListener(onFormSubmit);
    }
}

// in your application bootstrap:
Service myService = ... ;

Runnable submitHandler = () -> myService.doStuff(getDataFromUI());

// when constructing your UI, pass a reference to the submit handler.
// note: conceptually, it is entirely up to the UI to decide when to trigger the
// submit; thats perfect because interpreting user intent is part of the UIs job
// whereas performing the action is part of your service layer
Window myApplicationWindow = new MyAplicationWindow(submitHandler)

As to the repetition: for properties/configuration common to all buttons you can use the factory pattern, similar to what Doc Brown wrote in his answer.

I think this problem is in the domain of something called "Inversion of control".

You can either use an already implemented IOC(Inversion of control) framework or make something very lightweight for this, basically you would have:

class someService : ISomeService {}

public static class DependencyLibrary
{
    public static T Instantiate<T>()
    {
        if(T is ISomeService)
            return new SomeService();

        return null;
    }
}

public class Button : Element, IButton
{

    private ISomeService _someService

    public Button() : base()
    {
        _someService = DependencyLibrary.Instantiate<ISomeService>();
    }
}

DependencyLibrary is a class whose whole function is to keep references to resources and serve them to anybody who asks for a class of that type. Instead of returning a new SomeService every time it can cache the reference inside a list and give that back instead.

This gives you more separation between layers, since now neither the Button, neither the using class needs to know what ISomeService actually is, they can work with whatever the library gives back. If this service is a database for example, you can switch between the testing database and the production one with ease.

If you are interested you can take a look at these resources:

In-depth look at injection

IOC frameworks list for C#

Licensed under: CC-BY-SA with attribution
scroll top