Question

Here is the situation. We have two printers from different providers (manufacturers). We want top-level code to stay unaware of details about providers and just use uniform API. So I have started to extract an interface.

public interface IPrinterProvider {
    bool Connect(string comPort);
    bool IsConnected();
}

OK. Now, I realized that one printer requires Password property, but the other does not. So, what should I do?

And once more. As I understand, I'll have one or a couple of interfaces and a couple of implementors. But how will a caller work? Should I create a separate class, which might not implement any interfaces? For instance:

public class CommonPrinterProvider {
    private IPrinterProvider printerProvider;
    public CommonPrinterProvider(IPrinterProvider printerProvider) {
        this.printerProvider= printerProvider;
    }
}

So, two questions in total.

Was it helpful?

Solution

I would encapsulate printer "settings" (or, more accurately, "connection settings") into another class and have that in the interface. Somewhat like this:

public class PrinterSettings {
    public string Password { get; set; }
    public int Port { get; set; }
    /* .. others .. */
}

public interface IPrinterProvider {
    void Initialize(PrinterSettings settings);
    bool Connect(string comPort);
    bool IsConnected();
}

Then each implementation can deal with the settings in whatever way they see fit.

OTHER TIPS

One way would be to provide an inherited interface of IPrinterProvider. This new interface would have all the properties etc. that the password addition would add:

public interface IPrinterProvider
{
    bool Connect(string comPort);
    bool IsConnected();
}

public interface IPasswordPrinterProvider : IPrinterProvider
{
    string Password { get; set; }
}

This way the inherited interface contains all the same things that IPrinterProvider, but also extends those on its own. There will be no burden for those classes that implement the original IPrinterProvider without the password option.

It's better to unify your interface as much as possible. Sure interface implementations (classes) will have differences but dealing with them should be hidden in the strategies. The caller should work with interface and it's better to put instantiation to the IoC layer. The next step would be to create the services that would bring all needed settings for the certain implementation. Each service type would be used by each separate provider. Then you'll have a nice SOC. At this level you'll have parallel structures with same interface and implementing an Abstract Factory it's a perfect fit.

You could just leave your interface as is and implement one class that recieves a password and other that doesnt:

public class PasswordPrinterProvider : IPrinterProvider
{
     private readonly string password;
     public PasswordPrinterProvider(string password)
     {
         this.password = password;
     }
     public bool Connect(string comPort) {...}
     public bool IsConnected() {...}
}

You could use something like this... somewhat similar to factory pattern.

Abstract class:

public abstract class PrinterProvider
{
    public string Password{get;private set;}
    public abstract bool connect(string port);
    public bool IsConnected()
    {
        return true;
    }
}

ConcreteClass 1:

public class PrinterCompany1 : PrinterProvider
{
    public override bool connect(string port)
    {
        // some code here
        // If it needs password
        return true;
    }
}

ConcreteClass 2:

public class PrinterCompany2:PrinterProvider
{
    // Printer that doesnt need password
    public override bool connect(string port)
    {
        return false;
    }
}

And finally to access all these concrete classes,with the help of dynamic polymorphism...

        PrinterProvider provider;

        // First provider
        provider = new PrinterCompany1();
        provider.connect("temp");
        // Second provider
        provider = new PrinterCompany2();
        provider.connect("temp2");

Refer factory pattern for more detailed description...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top