派生型(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 件のコメント :
コメントを投稿