Dart で記載しています。https://dartpad.dev/

むかしむかし

あるところに鳥と魚がいました。

void main() {
  Bird().move();
  Fish().move();
}

class Bird {
  void move() {
    print('move');
    print('by fly');
  }
}

class Fish {
  void move() {
    print('move');
    print('by swim');
  }
}

Inheritance(継承)

どちらも動物ですので Inherit することにしました。

void main() {
  Bird().move();
  Fish().move();
}

class Animal {
  void move() {
    print('move');
  }
}

class Bird extends Animal {
  @override
  void move() {
    super.move();
    print('by fly');
  }
}

class Fish extends Animal {
  @override
  void move() {
    super.move();
    print('by swim');
  }
}

Mixins (注入)

そこへアヒルがきました。

// GaGa! (I can fly and swim. Should I extend bird? ... or fish?)
class Duck {}

Inherit では表現できないので Mixin することにしました。

void main() {
  Bird().move();
  Fish().move();
  Duck().move();
}

class Animal {
  void move() {
    print('move');
  }
}

mixin CanFly {
  void fly() {
    print('by fly');
  }
}

mixin CanSwim {
  void swim() {
    print('by swim');
  }
}

class Bird extends Animal with CanFly {
  @override
  void move() {
    super.move();
    fly();
  }
}

class Fish extends Animal with CanSwim {
  @override
  void move() {
    super.move();
    swim();
  }
}

class Duck extends Animal with CanFly, CanSwim {
  @override
  void move() {
    super.move();
    fly();
    swim();
  }
}

Composition (継承、委譲)

アヒルに電脳化手術が施され、コンピュータが埋め込まれた電脳アヒルになりました。

(鳥と魚は逃げ出してしまいました。)

電脳アヒルはハイテクなので、生命、宇宙、そして万物についての究極の疑問の答えを導きます。

電脳アヒルはコンピュータを Composit して計算を行わせます。

void main() {
  CyberDuck().move();
}

class Animal {
  void move() {
    print('move');
  }
}

mixin CanFly {
  void fly() {
    print('by fly');
  }
}

mixin CanSwim {
  void swim() {
    print('by swim');
  }
}

class Computer {
  void calc() {
    print('42');
  }
}

class CyberDuck extends Animal with CanFly, CanSwim {
  final Computer computer = Computer();

  @override
  void move() {
    super.move();
    fly();
    swim();
    computer.calc();
  }
}

徒然なるままに

  • Inheritance は上から下への縦方向の矢印
  • Composition は内から外への横方向の矢印
  • Mixins は外から内への横方向の矢印

Inheritance と Composition はよく対比して語られる。

Inheritance は記載するコード量が少なくて済むが複雑性が増していくほど辛くなる。一方 Composition は Inheritance 対比、記述量が多くなるが複雑性に耐性がある。

Composition over inheritance などと言われているように Composition が好まれる風潮。意図的に Inheritance をサポートしない言語もある。

Composition over inheritance - Wikipedia

結局使い分けだと思う。

システムの中でもそれほど複雑にならない部分、かつコードの変更がめったに発生しそうにない部分、そして疑いようのない親子関係であるものについては Inheritance で良いのでは。

Composition だと記述量が多くなってしまう点の対策は Mixins と組み合わせて使用すること。ちょうど先ほど載せた Wikipedia でもそのことが言及されている。

Composition over inheritance

Drawbacks

One common drawback of using composition instead of inheritance is that methods being provided by individual components may have to be implemented in the derived type, even if they are only forwarding methods (this is true in most programming languages, but not all; see Avoiding drawbacks.) In contrast, inheritance does not require all of the base class’s methods to be re-implemented within the derived class. Rather, the derived class only needs to implement (override) the methods having different behavior than the base class methods. This can require significantly less programming effort if the base class contains many methods providing default behavior and only a few of them need to be overridden within the derived class.

Avoiding drawbacks

This drawback can be avoided by using traits, mixins, (type) embedding, or protocol extensions.

具体例は以下のブログ記事で説明してくださっているような感じになる。

コンポジションとミックスイン【Python】

おわり

成長した電脳アヒルは、自分がアヒルではなく美しい白鳥であったことに気付いたのでした。めでたしめでたし。