9

Suppose I have a various entities in my model (using EF), say User, Product, Invoice and Order.

I am writing a user control that can can print the summaries of entity objects in my application where the entities belong to pre-decided set, in this case I say that summaries of User and Product can be summarized.

The summaries will all only have a ID and a description, so I create a simple interface for this:

 public interface ISummarizableEntity {     
       public string ID { get; }    
       public string Description { get; } 
 }

Then for the entities in question, I create a partial class that implements this interface:

public partial class User : ISummarizableEntity
{
    public string ID
    {
        get{ return UserID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age); }
    }
}

public partial class Product: ISummarizableEntity
{
    public string ID
    {
        get{ return ProductID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department); }
    }
}

This way my user control / partial view can just bind to any collection of ISummarizableEntity and doesn't need to be interested in the source at all. I have been told that interfaces shouldn't be used as datatypes but I didn't get more information than that. As far as I can see, although interfaces normally describe behavior, just using properties isn't an anti-pattern in itself as properties are just syntactic sugar for getters/setters anyway.

I could create a concrete datatype and map from the entities to that but I can't see the benefit. I could make the entity objects inherit from an abstract class and then define the properties but then I am locking the entities to no further use as we can't have multiple inheritance. I am also open to having any object being ISummarizableEntity if I wanted (obviously I would rename the interface)

The solution I am using in my mind is maintainable, extensible, testable and fairly robust. Can you see the anti-pattern here?

  • Is there any reason you prefer this over having something like EntitySummary, with User and Product each having a method like public EntitySummary GetSummary()? – Ben Aaronson Mar 4 '15 at 13:23
  • @Ben, you suggest a valid option. But it would still require the definition of an interface that lets the caller know they can expect an object to have a GetSummary() method. It's essentially the same design with an added level of modularity in the implementation. Maybe even a good idea if the summary needs to live on its own (however briefly) separate from its source. – Kent A. Mar 4 '15 at 13:29
  • @KentAnderson I agree. It may or may not actually be a good idea, depending on the overall interface of these classes and how summaries are used. – Ben Aaronson Mar 4 '15 at 13:33
17

Interfaces don't describe behaviour. Quite the opposite, sometimes.

Interfaces describe contracts, such as "if I am to offer this object to any method that accepts an ISummarizableEntity, this object must be an entity that is able to summarize itself" -- in your case, that is defined as being able to return a string ID and a string Description.

That's a perfect use of interfaces. No anti-pattern here.

  • 2
    "Interfaces don't describe behaviour." How is "summarize itself" not a behavior? – Doval Mar 4 '15 at 13:56
  • 2
    @ThomasStringer, inheritance, from an OO purist view, implies a common ancestry (e.g., a square and a circle are both shapes). In OP's example, a User and a Product share no reasonable common ancestry. Inheritance in this case would be a clear anti-pattern. – Kent A. Mar 4 '15 at 14:40
  • 2
    @Doval: I guess the name of the interface may describe the expected behaviour. But it doesn't have to; the interface could equally be named IHasIdAndDescription and the answer would be the same. The interface itself doesn't describe behaviour, it describes expectations. – pdr Mar 4 '15 at 15:07
  • 2
    @pdr If you send 20V through a headphone jack, bad things will happen. The shape is not enough; there is a very real and very important expectation of what kind of signal is going to come through that plug. This is precisely why pretending that interfaces don't have behavior specifications attached to them is wrong. What can you do with a List that doesn't behave like a list? – Doval Mar 4 '15 at 16:03
  • 3
    An electrical plug with the appropriate interface may fit into the outlet, but that doesn't mean it will conduct electricity (the desired behavior). – JeffO Mar 4 '15 at 16:34
5

You have chosen the better path for this design because you are defining a specific type of behavior that will be required of multiple, different, types of objects. Inheritance in this case would imply a common relationship between the classes that does not actually exist. In this case, composability is favored over inheritance.

  • 3
    Interfaces have nothing to do with inheritance. – DougM Mar 4 '15 at 13:28
  • 1
    @DougM, maybe I didn't say it well, but I'm pretty sure we agree. – Kent A. Mar 4 '15 at 13:31
1

Interfaces that only carry properties should be avoided since :

  • it obfuscates the intent : you solely need a data container
  • it encourages inheritance : probability that someone will mix concerns in the future
  • it prevents serialization

Here you are mixing two concerns :

  • summary as a data
  • summary as a contract

A summary is made of two strings : an id and a description. This is plain data :

public class Summary {
    private readonly string id;
    private readonly string description;
    public Summary(string id, string description) {
        this.id = id;
        this.description = description;
    }
    public string Id { get { return id; } }
    public string Description { get { return description; } }
}

Now that you have defined what a summary is you want to define a contract :

public interface ISummarizableEntity {
    public Summary GenerateSummary();
}

Note that using intelligence in getters is an anti-pattern and should be avoided : it should be located in functions instead. Here is how implementations look like :

public partial class User : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = UserID.ToString();
        var description = String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age);
        return new Summary(id,description);
    }
}

public partial class Product : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = ProductID.ToString();
        var description = String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department);
        return new Summary(id,description);
    }
}
  • "Interfaces that only carry properties should be avoided" I disagree. Provide reasoning why do you think so. – Euphoric Feb 1 '16 at 7:33
  • You are right I added some details – vanna Feb 1 '16 at 9:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.