2

How does the Interface Segregation Principle apply to convenience/helper methods? For instance:

I want to create an interface that represents business partners. The bare minimum that I would need would be a setter and a getter method that would set or get the entire list of partners:

Interface Partners {
  method getList();
  method setList();
}

I also want to have a contains() method to tell me if a certain person was included in the list of partners. I consider this a helper or convenience method, because all it does it call getPartners() and then check if the given person is in that list.

My understanding of the Interface Segregation Principle is that I should separate my contains() method into a separate interface, since someone might want to implement my Partners interface without providing an implementaiton for this unnecessary helper method. In my example, its not a big deal, but the list of helper methods can quickly grow long (addPartner, addPartnerByID, addPartnerByUserid, etc.), so this is a practical problem.

My concern is that I'm finding it quite difficult to pick a name for an interface to hold my contains() method that does not sound cumbersome, and I think any time you have this much trouble naming something, it is a red flag that there is something wrong in your design. It does not seem right to have an interface named PartnersSupportingSetInclusionChecks, nor does it seem good to have an interface just named PartnerHelperMethods.

How do I apply the Interface Segregation Principle to such methods?

Dave Schweisguth
  • 36,475
  • 10
  • 98
  • 121
Chris
  • 21
  • 2

2 Answers2

1

since someone might want to implement my Partners interface without providing an implementation for this unnecessary helper method

emphasis mine

Please by all means have a contains() method if you think it's important to have in your API. Especially if all your client code currently use one.

The Interface Segregation Principle is to keep totally unrelated methods out of the interface. It looks like you are trying to implement a Repository which should have a get, contains etc methods to see what elements are in the repository and a way to retrieve them.

If you had other kinds of methods that had nothing to do with getting or setting Partners, then the ISP should be applied to make a different interface for that.

However, you may want to think about separating your getting/contains methods from your setting/adding methods if you think you will have clients that treat this repository as read-only and should not be allowed to modify it, but you don't have to.

dkatzel
  • 31,188
  • 3
  • 63
  • 67
0

The following answer is based on C# language. It might not be valid in another language.

I want to create an interface that represents business partners

This first sentence tells me that you probably don´t need an interface, but a top-level abstract class. And it is very important to distinguish whether we need an interface or an abstract class.

Abstract classes represent hierarchies, where each descendant of that hierarchy is a specialization, therefore you can adding more members in order to enrich the family. In this case, the relationship describes “This X is a Y”

Interfaces represent a set of characteristics and behavior not linked to any hierarchy. Therefore, the main intention is to link different kind of classes that will have the same features or behaviors. The relationship describes “This X can do Y”

So, assuming that what fits better with your description is an abstract class, I suggest the following:

One option could be set the methods "getList()" and "setList()" as non-abstract methods and provide into the abstract class a field to store the list

public abstract Partner
{
      List<Partner> list;

      public void SetList(List<Partner> list)
      {
          list = list;
      }
      public List<Partner> GetList(Partner partner)
      {
          return list;
      }
}

So, the method "Contains" can be non-abstract aswell, so you don't force the descendant classes to provide an implementation.

public bool Contains(Partner partner)
{
    return list.Contains(partner);
}

And let's suppose that in the future you want to add new helpers methods. Those methods can be new non-abstract methods into the base class, so you will not affect your current descendants of "Partner".

If you need to modify the implementation of helpers methods, you can set it as "virtual" so that the descendant classes can override the base implementation.

public virtual void AddPartner(Partner partner)
{
    list.Add(partner);
}