goran85
goran85

Reputation: 503

Extend Interface Implementation?

I have a small object factory that creates two types of objects. Now I want to add new method to a 2nd object but without changing interface since I must implement that method in the 1st object too. How to do it?

public class LookupFactory
{
    public ILookups CreateLookups()
    {
        ILookups dbLookup = null;
        var databaseType = ConfigurationManager.AppSettings["databaseType"].ToString();

        switch (databaseType.ToLower())
        {
            case "oracle":
                dbLookup = new Lookups();
                break;
            case "mssql":
                dbLookup = new SqlLookups();
                break;
        }

        return dbLookup;
    }
}

My interface looks like this:

public interface ILookups
{
    List<Region> GetRegions(string language);

    List<Industry> GetIndustries(string language);

    List<Dimension> GetDimensions(string language);

    List<SubjectType> GetSubjectTypes(string language);
 }

I want to add method GetPeople to SqlLookups object only.

Upvotes: 0

Views: 348

Answers (2)

Backs
Backs

Reputation: 24903

Well, if two classes implement one interface they must implement all methods. So, if you want to add new method to your interface, you have to implement it in both Lookups and SqlLookups. Possible solutions:

  1. Create new interface IExtendedLookups : ILookups and add new method to IExtendedLookups and make class SqlLookups : IExtendedLookups Your factory should return ILookups but later in code you have to check returned value:

    var lookups = factory.CreateLookups();
    var extendedLookups = lookups as IExtendedLookups;
    if (extendedLookups != null)
    {
        //...call extendedLookups.GetPeople();
    }
    
  2. Add new method to ILookups, implement in both classes but in Lookups do it like this:

    public List<People> GetPeople()
    {
        throw new NotSupportedException();
    }
    

Upvotes: 3

Onur
Onur

Reputation: 5205

You have to ask yourself the question how it should work from the "consumer side".

As a starting point I'd do it this way:

  1. Generate a refined interface implemented only by certain classes:

    public interface ILookups
    {
        List<Region> GetRegions(string language);
        List<Industry> GetIndustries(string language);
        List<Dimension> GetDimensions(string language);
        List<SubjectType> GetSubjectTypes(string language);
    
        // maybe add this
        // this makes it clear to the consumer that it could receive an extended lookup
        // one class returns "this", the other "null" 
        IExtendedLookUps GetExtendedOrNull { get;}
    }
    
    public interface IExtendedLookups : ILookups
    {
        List<People> GetPeople();
    }
    
     void consumerCode()
     {
        ILookups lookups = factory.CreateLookups();
    
        // code that works for both cases
        lookups.GetRegions("en");
    
        // do something special if it implements IExtendedLookups
        if (lookups is IExtendedLookups)
        {
            var extendedLookups = lookups as IExtendedLookups;
            extendedLookups.GetPeople();
        }
        // or with the additional interface property:
        var maybeExtendedLookups = lookups.GetExtendedOrNull;
        if (maybeExtendedLookups  != null)
        {
            maybeExtendedLookups.GetPeople();
        }
    
     }
    
  2. If the extra method is relevant only for a single purpose (e.g. generating a certain report), then maybe include this report generation in the interface.

  3. If there is a suitable "default" value (like an empty list in your case), add it to the other class. If there is no suitable default, don't do it.

As a summary: It all depends on how you want to use it. Design from usage to implementation not the other way round!

Upvotes: 1

Related Questions