Why not inherit from List?

前端 未结 27 2208
悲哀的现实
悲哀的现实 2020-11-21 05:39

When planning out my programs, I often start with a chain of thought like so:

A football team is just a list of football players. Therefore, I should

27条回答
  •  谎友^
    谎友^ (楼主)
    2020-11-21 06:19

    Prefer Interfaces over Classes

    Classes should avoid deriving from classes and instead implement the minimal interfaces necessary.

    Inheritance breaks Encapsulation

    Deriving from classes breaks encapsulation:

    • exposes internal details about how your collection is implemented
    • declares an interface (set of public functions and properties) that may not be appropriate

    Among other things this makes it harder to refactor your code.

    Classes are an Implementation Detail

    Classes are an implementation detail that should be hidden from other parts of your code. In short a System.List is a specific implementation of an abstract data type, that may or may not be appropriate now and in the future.

    Conceptually the fact that the System.List data type is called "list" is a bit of a red-herring. A System.List is a mutable ordered collection that supports amortized O(1) operations for adding, inserting, and removing elements, and O(1) operations for retrieving the number of elements or getting and setting element by index.

    The Smaller the Interface the more Flexible the Code

    When designing a data structure, the simpler the interface is, the more flexible the code is. Just look at how powerful LINQ is for a demonstration of this.

    How to Choose Interfaces

    When you think "list" you should start by saying to yourself, "I need to represent a collection of baseball players". So let's say you decide to model this with a class. What you should do first is decide what the minimal amount of interfaces that this class will need to expose.

    Some questions that can help guide this process:

    • Do I need to have the count? If not consider implementing IEnumerable
    • Is this collection going to change after it has been initialized? If not consider IReadonlyList.
    • Is it important that I can access items by index? Consider ICollection
    • Is the order in which I add items to the collection important? Maybe it is an ISet?
    • If you indeed want these thing then go ahead and implement IList.

    This way you will not be coupling other parts of the code to implementation details of your baseball players collection and will be free to change how it is implemented as long as you respect the interface.

    By taking this approach you will find that code becomes easier to read, refactor, and reuse.

    Notes about Avoiding Boilerplate

    Implementing interfaces in a modern IDE should be easy. Right click and choose "Implement Interface". Then forward all of the implementations to a member class if you need to.

    That said, if you find you are writing lots of boilerplate, it is potentially because you are exposing more functions than you should be. It is the same reason you shouldn't inherit from a class.

    You can also design smaller interfaces that make sense for your application, and maybe just a couple of helper extension functions to map those interfaces to any others that you need. This is the approach I took in my own IArray interface for the LinqArray library.

提交回复
热议问题