派生型(Subtyping)については, is-a - Wikipediaにその説明が載っていますが, 確かにここでも, 継承が必ずis-a関係を構築するとは書かれてはいません.
数理科学的バグ撲滅方法論のすすめ - 第4回 関数型言語とオブジェクト指向,およびOCamlの"O"について - ITpro に, その反例を示したソースコードがありますが, OCamlなのであまり実感わきません. オブジェクト指向言語は, JavaかPythonくらいしか使ったことがないので, Pythonでとりあえず書き直してみました.
Pointクラスを継承したColoredPointクラス.
class Point: def __init__(self, x, y): self.x = x self.y = y def equals(self, another): return self.x == another.x and self.y == another.y class ColoredPoint(Point): def __init__(self, x, y, c): self.x = x self.y = y self.c = c def equals(self, another): xeq = self.x == another.x yeq = self.y == another.y ceq = self.c == another.c return xeq and yeq and ceqこの例では, 確かにPointクラスが継承されていますが, equalsがオーバーライドされています. 一方で, Pointクラス間ではequals関数で比較できるように実装されています.
PointクラスとColoredPointクラスのインスタンスがis-a関係ならば, 当然, Pointクラスのインスタンス⇔ColoredPointクラスのインスタンス間で, インスタンスのequalityの比較が可能なはずです.
>>> ColoredPoint(1,2,3).equals(ColoredPoint(1,2,3)) True >>> ColoredPoint(1,2,3).equals(Point(1,2)) Traceback (most recent call last): File "で, 比較してみると, エラーが発生する. という現象が反例としてあげられるため, 継承≠is-aということのようです.", line 1, in File "notisa.py", line 16, in equals ceq = self.c == another.c AttributeError: Point instance has no attribute 'c'
面白いのは, 継承しなくても, is-aの関係が成立してしまうケースが存在することで, 次のFruitとOarngeクラスの例が考えられます.
class Fruit: def __init__(self, price): self.price = price def equals(self, another): return self.price == another.price class Orange: def __init__(self, price): self.price = price def equals(self, another): return self.price == another.price厳密な意味(?)でis-a関係が成立しているわけではないですが, equalsによる比較ができてしまい, 一種の部分型(is-a関係)のような振る舞いが可能になります. OCamlなどでは, この辺を型推論により自動的に型付けしてくれるようで, このような型を構造的部分型(structual subtyping)と呼ぶようです(前述のITProの記事より).
0 件のコメント :
コメントを投稿