2017-09-14 9 views
0

Je souhaite soumettre un problème de POO. Peut-être qu'il a été résolu ailleurs, mais je n'a pas pu le trouver ...Ne pas autoriser une instance de cercle à accepter un Point3D comme centre

Imaginez quelque chose comme ça (python-like pseudo-code)

class Point: 
    x: int 
    y: int 

    # Some methods here  

class Point3D(Point): 
    z: int 

class Circle: 
    center: Point 
    radius: int 

    # Some methods here 

class Sphere(Circle): 
    center: Point3D 

Dans un statiquement typé langage - à moins que je faire une erreur - une instance Point3D passera en tant qu'attribut center pour Circle, puisqu'elle hérite de Point, qui doit être non autorisée, car elle se transformerait en une Sphere-like.

Comment pouvons-nous y parvenir sans perdre les méthodes de factorisation?

Répondre

1

Le Liskov Substitution Principle (LSP) indique que le remplacement d'une instance d'une classe de base par une instance d'une classe dérivée doit toujours fonctionner. Ceci est une caractéristique de base de la POO, pas un problème.

Le problème est dans votre modèle - considérons quelle est la relation entre un point 2D et un point 3D. Ayant Point3D Hériter de Point2D indique qu'un Point3Dest unPoint2D, qui est, tous les Point3D « s sont également Point2D » s. Mais cela ne correspond pas vraiment à ce que vous modélisez! En mathématiques, seuls les points 3D du plan 2D (ceux avec z == 0) sont en réalité des points 2D. Cette divergence est la source de cette échappatoire qui pourrait transformer votre Circle en une sphère.

Le modèle OOP pour cela pourrait en fait être le contraire: tous les points 2D sont points 3D, avec z == 0. Ainsi, Point2D héritant de Point3D aurait un sens. Cela ouvrirait cependant une nouvelle série de problèmes de mutabilité: si vous pouvez accéder à Point2D en tant que Point3D et que vous le modifiez, vous pouvez définir ses coordonnées z comme étant non nulles et se retrouver avec une incohérence Point2D ce n'est plus réellement 2D. LSP est à nouveau cassé.


Il est tentant de représenter la relation entre 2D et un point 3D en POO dans les deux sens:

  • Un point 3D contient une plus coordonnée qu'un point 2D ne pas utiliser, ainsi il devrait être la classe dérivée

... ou ...

  • Mathématiquement, un p 2D oints est également un point 3D, donc il devrait être la classe dérivée

... mais la ligne de fond est tout simplement que ni classe peut hériter de l'autre, parce que le LSP est cassé ou l'autre manière . Conservez-les en tant que classes distinctes, pommes avec pommes et Circle avec Point2D s, et utilisez d'autres fonctionnalités de langue si vous avez besoin de factoriser le code commun entre les points - la programmation générique, par exemple.

+0

Très clair, merci pour l'explication! Mais je pensais utiliser une super classe abstraite afin de [dry'] (https://en.m.wikipedia.org/wiki/Don%27t_repeat_yourself) ... (Il est maintenant même possible en python avec 'ABC 's aka Abstract Base Classes) La classe abstraite ne peut pas être instanciée,' Point2D' et 'Point3D' ne héritent pas l'un de l'autre, donc le LSP est respecté. Ton opinion? –

+0

Oui, cela serait valide, du moment que vous prenez soin de ne mettre dans la classe de base que des choses qui sont réellement communes aux deux types de points. – Quentin