We have a relatively big class. One of my colleagues thinks we must split this class into a base & child class to make it smaller and cleaner.

On the other hand, I believe when we know this parent will always have only just this one child, inheritance isn't an appropriate solution.

So imagine these classes:

public class Foo : Bar, IFoo
{    
    public Task DoSomething(SomeData someDate)
    {
    }
    // Some other public methods that are exposed in IFoo interface

}

public abstract class Bar
{
    protected readonly ISomeInjectedService _someInjectedService;
    public Bar(ISomeInjectedService someInjectedService)
    {
        _someInjectedService=someInjectedService;
    }
    // Some other private or protected methods
}

Or this class:

public class Foo : IFoo
{
    private readonly ISomeInjectedService _someInjectedService;
    public Foo(ISomeInjectedService someInjectedService)
    {
        _someInjectedService=someInjectedService;
    }
    // Some other private methods


    
    public Task DoSomething(SomeData someDate)
    {
    }
    // Some other public methods that are exposed in IFoo interface
}

The important point is, this new base class will never have another child. The question is: Is inheritance usage, justified here?

有帮助吗?

解决方案

Splitting a big class into smaller classes is primarily about separation of concerns. When the independent concerns (some prefer to reflect in terms of “reason to change”) are well identified then only can you reasonably decide about inheritance vs. composition.

The core question is: didn’t we accidentally during the growth period put together too many independent things? and how can we make them independent again? Your question does not allow us to provide advice on this aspect.

But in any case, you should make Foo a subclass of Bar only if the concept of Foo is a specialization of Bar. If you cannot think of other specializations ever, even in other projects, then there are big chances that you are going to misuse inheritance. It may solve some issue on the short term, but sooner or later it will backfire (probably by hiding better ways to refactor).

其他提示

Inheritance can be used as a tool to refactor out a new, smaller base class Bar from Foo, which can be tested, managed or used independently from its derivation. Moreover, it is a tool which allows to write more generalized code in terms of Bar, which is especially useful when there is more than one derived class (but which seems not to applicable to your situation).

Unfortunately, the goal mentioned in the title of the question, to make the child class Foo smaller, is not really reached by inheritance. Sure, the code in the class file gets smaller, but when it comes to debugging and testing Foo, inheritance does not make a good job of reducing the amount of code which has to be taken into account:

  • Foo still cannot be tested in isolation from the code which lives in Bar

  • When a method call to Foo shows up a bug, almost the same amount of code has to be analysed for finding the root cause (to be fair, there may be cases where you can write tests for Bar which excludes certain root causes for a bug in Foo).

Hence before using inheritance, one should definitely check if the goal of making the original class "smaller" is not better reached by using composition instead of inheritance. For example, this would allow Bar to be replaced by some MockBar for the purpose of testing Foo. The drawback is, it might require more refactoring effort, and more delegational code than inheritance. Another option might be not to refactor now, since the effort of introducing inheritance and the additional overhead in code might currently not be balanced by the questionable benefit of having two smaller code files of strongly coupled code instead of one.

So each of the possible choices has advantages and drawbacks - I hope my remarks above can help you to compare them against each other a little bit better.

Subclassing in this case is kind of cheating. If there is functionality that you can extract into a separate useful class, that might be a better choice.

许可以下: CC-BY-SA归因
scroll top