Interfaces on an abstract class

My coworker and I have different opinions on the relationship between base classes and interfaces. I’m of the belief that a class should not implement an interface unless that class can be used when an implementation of the interface is required. In other words, I like to see code like this:

interface IFooWorker { void Work(); }

abstract class BaseWorker {
    ... base class behaviors ...
    public abstract void Work() { }
    protected string CleanData(string data) { ... }
}

class DbWorker : BaseWorker, IFooWorker {
    public void Work() {
        Repository.AddCleanData(base.CleanData(UI.GetDirtyData()));
    }
}

The DbWorker is what gets the IFooWorker interface, because it is an instantiatable implementation of the interface. It completely fulfills the contract. My coworker prefers the nearly identical:

interface IFooWorker { void Work(); }

abstract class BaseWorker : IFooWorker {
    ... base class behaviors ...
    public abstract void Work() { }
    protected string CleanData(string data) { ... }
}

class DbWorker : BaseWorker {
    public void Work() {
        Repository.AddCleanData(base.CleanData(UI.GetDirtyData()));
    }
}

Where the base class gets the interface, and by virtue of this all inheritors of the base class are of that interface as well. This bugs me but I can’t come up with concrete reasons why, outside of “the base class cannot stand on its own as an implementation of the interface”.

What are the pros & cons of his method vs. mine, and why should one be used over another?

5

I’m of the belief that a class should not implement an interface unless that class can be used when an implementation of the interface is required.

BaseWorker fulfills that requirement. Just because you can’t directly instantiate a BaseWorker object doesn’t mean you can’t have a BaseWorker pointer that fulfills the contract. Indeed, that’s pretty much the whole point of abstract classes.

Also, it’s difficult to tell from the simplified example you posted, but part of the problem may be that the interface and the abstract class are redundant. Unless you have other classes implementing IFooWorker that do not derive from BaseWorker, you don’t need the interface at all. Interfaces are just abstract classes with some additional limitations that make multiple inheritance easier.

Again being difficult to tell from a simplified example, the use of a protected method, explicitly referring to the base from a derived class, and the lack of an unambiguous place to declare the interface implementation are warning signs that you are inappropriately using inheritance instead of composition. Without that inheritance, your whole question becomes moot.

5

I’d have to agree with your coworker.

In both examples you give, BaseWorker defines the abstract method Work(), which means that all subclasses are capable of meeting IFooWorker’s contract. In this case, I think BaseWorker should implement the interface, and that implementation would be inherited by its subclasses. This will save you from having to explicitly indicate that each subclass is indeed an IFooWorker (the DRY principle).

If you weren’t defining Work() as a method of BaseWorker, or if IFooWorker had other methods that subclasses of BaseWorker wouldn’t want or need, then (obviously) you’d have to indicate which subclasses actually implement IFooWorker.

6

I generally agree with your coworker.

Let’s take your model: the interface is implemented only by the child classes, even though the base class also enforces the exposure of IFooWorker methods. First off, it’s redundant; whether the child class implements the interface or not, they are required to override the exposed methods of BaseWorker, and likewise any IFooWorker implementation must expose the functionality whether they get any help from BaseWorker or not.

This additionally makes your hierarchy ambiguous; “All IFooWorkers are BaseWorkers” is not necessarily a true statement, and neither is “All BaseWorkers are IFooWorkers”. So, if you want to define an instance variable, parameter, or return type that could be any implementation of either IFooWorker or BaseWorker (taking advantage of the common exposed functionality which is one of the reasons to inherit in the first place), neither of these is guaranteed to be all-encompassing; some BaseWorkers won’t be assignable to a variable of type IFooWorker, and vice versa.

Your coworker’s model is much easier to use and to replace. “All BaseWorkers are IFooWorkers” is now a true statement; you can give any BaseWorker instance to any IFooWorker dependency, no problems. The opposite statement “All IFooWorkers are BaseWorkers” is not true; that allows you to replace BaseWorker with BetterBaseWorker and your consuming code (which depends on IFooWorker) won’t have to tell the difference.

2

I need to add something of a warning to these answers. Coupling the base class to the interface creates a force in the structure of that class. In your basic example, it’s a no brainer that the two should be coupled, but that may not hold true in all cases.

Take Java’s collection framework classes:

abstract class AbstractList
class LinkedList extends AbstractList implements Queue

The fact that the Queue contract is implemented by LinkedList did not push the concern into AbstractList.

What’s the distinction between the two cases? The purpose of BaseWorker was always (as communicated by its name and interface) to implement operations in IWorker. The purpose of AbstractList and that of Queue are divergent, but a descenant of the former can still implement the latter contract.

5

I would ask the question, what happens when you change IFooWorker, such as adding a new method?

If BaseWorker implements the interface, by default it will have to declare the new method, even if it’s abstract. On the other hand, if it doesn’t implement the interface, you’ll only get compile errors on the derived classes.

For that reason, I’d make the base class implement the interface, since I might be able to implement all the functionality for the new method in the base class without touching the derived classes.

First think of what an abstract base class is, and what an interface is. Consider when you would use one or the other and when you would not.

It’s common for people to think of both being very similar concepts, in fact it’s a common interview question (difference between the two is??)

So an abstract base class gives you something interfaces can’t which is default implementations of methods. (There’s other stuff, in C# you can have static methods on an abstract class, not on an interface for example).

As an example, one common use of this is with IDisposable. The abstract class implements IDisposable’s Dispose method, which means any derived version of the base class will automatically be disposable. You can then play with several options. Make Dispose abstract, forcing derived classes to implement it. Provide a virtual default implementation, so they don’t, or make it neither virtual or abstract and have it call virtual methods called things like BeforeDispose, AfterDispose, OnDispose or Disposing for example.

So any time all derived classes need to support the interface, it goes on the base class. If only one or some need that interface it would go on the derived class.

That’s all actually a gross over simplification. Another alternative is to have derived classes not even implement the interfaces, but provide them via an adapter pattern. An example of this I saw recently was in IObjectContextAdapter.

I am still years away from fully grasping the distinction between an abstract class and an interface. Every time I think I get a handle on the basic concepts, I go looking on stackexchange and I’m two steps back. But a few thoughts on the topic and the OPs question:

First:

There are two common explanations of an interface:

  1. An interface is a list of methods and properties that any class can implement, and by implementing an interface, a class guarantees those methods (and their signatures) and those properties (and their types) will be available when “interfacing” with that class or an object of that class. An interface is a contract.

  2. Interfaces are abstract classes that don’t/can’t do anything. They’re useful because you can implement more than one, unlike those mean parent classes. Like, I could be an object of class BananaBread, and inherit from BaseBread, but that doesn’t mean I can’t also implement both the IWithNuts and the ITastesYummy interfaces. I could even implement the IDoesTheDishes interface, because I’m not just bread, yknow?

There are two common explanations of an abstract class:

  1. An abstract class is, yknow, the thing not what the thing can do. It’s like, the essence, not really a real thing at all. Hang on, this will help. A boat is an abstract class, but a sexy Playboy Yacht would be a sub class of BaseBoat.

  2. I read a book on abstract classes, and maybe you should read that book, because you probably don’t get it and will do it wrong if you haven’t read that book.

By the way, the book Citers always seem impressive, even if I still walk away confused.

Second:

On SO, someone asked a simpler version of this question, the classic, “why use interfaces? What’s the difference? What am I missing?” And one answer used an air force pilot as a simple example. It didn’t quite land, but it sparked some great comments, one of which mentioned the IFlyable interface having methods like takeOff, pilotEject, etc. And this really clicked for me as a real-world example of why interfaces are not just useful, but crucial. An interface makes an object/class intuitive, or at least gives the sense that it is. An interface isn’t for the benefit of the object or the data, but for something that needs to interact with that object. The classic Fruit->Apple->Fuji or Shape->Triangle->Equilateral examples of inheritance are a great model for taxonomically understanding a given object based on its descendants. It informs the consumer and the processors about its general qualities, behaviors, whether the object is a group of things, will hose your system if you put it in the wrong place, or describes sensory data, a connector to a specific data store, or financial data needed to make payroll.

A specific Plane object may or may not have a method for an emergency landing, but I’m going to be pissed off if I assume its emergencyLand like every other flyable object only to wake up covered in DumbPlane and learn that the developers went with quickLand because they thought that it was all the same. Just like how I would be frustrated if every screw manufacturer had their own interpretation of righty tighty or if my TV didn’t have the volume increase button above the volume decrease button.

Abstract classes are the model that establishes what any descendent object must have to qualifiy as that class. If you don’t have all the qualities of a duck, it doesn’t matter that you have the IQuack interface implemented, your just a weird penguin. Interfaces are the things that make sense even when you can’t be sure of anything else. Jeff Goldblum and Starbuck were both able to fly alien spaceships because the interface was reliably similar.

Third:

I agree with your coworker, because sometimes you need to enforce certain methods at the very start. If you’re creating an Active Record ORM, it needs a save method. This isn’t up to the subclass that can be instantiated. And if the ICRUD interface is portable enough to not be exclusively coupled to the one abstract class, it can be implemented by other classes to make them reliable and intuitive for anyone already familiar with any of the descendant classes of that abstract class.

On the other hand, there was a great example earlier of when to not jump to tying an interface to the abstract class, because not all list types will (or should) implement a queue interface. You said this scenario happens half the time, which means you and your coworker are both wrong half the time, and thus the best thing to do is argue, debate, consider, and if they turn out to be right, acknowledge and accept the coupling. But don’t become a developer who follows a philosophy even when it isn’t not the best one for the job at hand.

There is another aspect to why the DbWorker ought to implement IFooWorker, as you suggest.

In case of your coworker’s style, if for some reason a later refactoring occurs and the DbWorker is deemed not to extend the abstract BaseWorker class, DbWorker loses the IFooWorker interface. This could, but not necessarily, have an impact on clients consuming it, if they expect the IFooWorker interface.

To start off, I like to define interfaces and abstract classes differently:

Interface: a contract that each class must fulfill if they are to implement that interface
Abstract class: a general class (i.e vehicle is an abstract class, while porche911 is not)

In your case, all workers implement work() because that is what the contract requires them to. Therefore your base class Baseworker should implement that method either explicitly or as a virtual function. I would suggest you to put this method in your base class because of the simple fact that all workers need to work(). Therefore it is logical that your baseclass (even though you cannot create a pointer of that type) includes it as a function.

Now, DbWorker does satisfy the IFooWorker interface, but if there is a specific way that this class does work(), then it really needs to overload the definition inherited from BaseWorker. The reason it should not implement the interface IFooWorker directly is that this is not something special to DbWorker. If you did that everytime you implemented classes similar to DbWorker then you would be violating DRY.

If two classes implement the same function in different ways, you could start looking for the greatest common superclass. Most of the time you will find one. If not, either keep looking or give up and accept that they don’t have sufficient things in common to make a base class.

Wow, all these answers and none pointing out that the interface in the example serves no purpose whatsoever. You don’t use inheritance and an interface for the same method, it is pointless. You use one or the other. There are plenty questions on this forum with answers explaining the benefits of each and the senarios that call for one or the other.

4

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật