Est-il mauvais de créer des classes dont le seul but est d'être converti implicitement en une autre classe?


10

Imaginez une situation où nous utilisons une bibliothèque qui vous permet de créer des Circleobjets, où vous pouvez spécifier le rayon et le centre du cercle pour le définir. Cependant, pour une raison quelconque, il prend également un flavourparamètre requis . Maintenant, disons que j'ai vraiment besoin d'utiliser Circledans ma propre application, mais pour les besoins de mon application, je peux définir la saveur à Flavours.Cardboardchaque fois.

Pour "résoudre" cela, je crée ma propre Circleclasse dans un espace de noms différent, qui ne prend radiuset centercomme paramètres, mais a un convertisseur implicite à la Circleclasse de la bibliothèque externe qui crée juste un Circle(this.radius, this.center, Flavours.Cardboard)objet. Donc, partout où j'ai besoin de l'autre type de Circle, je laisse la conversion automatique avoir lieu.

Quelles sont les conséquences de la création d'une telle classe? Y a-t-il de meilleures solutions? Cela ferait-il une différence si mon application était une API construite au-dessus de cette bibliothèque externe, destinée à être utilisée par d'autres programmeurs?


Cela semble être une variation du modèle d'adaptateur , bien qu'il semble être d'une valeur douteuse ici (il s'agit simplement d'une commodité pour éviter de définir un paramètre).
Robert Harvey

5
Pourquoi ne pas créer une MakeCircle fonction ?
user253751

1
@immibis Thay a été ma première pensée. Lorsque je crée des jeux, je crée souvent une fonction dans le sens makePlayeroù elle-même n'accepte que les accords pour placer le joueur, mais les délègue à un constructeur beaucoup plus complexe.
Carcigenicate

Réponses:


13

Bien que ce ne soit pas toujours mauvais, il est assez rare que les conversions implicites soient votre meilleure option.

Il y a des problèmes.

  1. Les conversions implicites ne sont pas très lisibles.
  2. Étant donné que vous créez un nouvel objet, toute modification apportée à l'objet d'origine ne sera pas vue par celui vers lequel vous vous convertissez, ce qui entraînera des bogues.
  3. Si vous jetez l'objet, ce sont des déchets supplémentaires à nettoyer.
  4. S'il y a un problème, cela se produira lorsque la conversion se produira, pas lorsque la chose sera créée, ce qui rendra les bogues plus difficiles à localiser.

En général, il existe de meilleures solutions.

  1. Créez votre propre wrapper mince qui utilise l'autre classe / framework en interne.
  2. Créez une méthode d'assistance qui prend les arguments de constuctor que vous voulez et fournit celui qui est fixe, renvoyant l'objet réel sans avoir à spécifier l'argument qui ne vous intéresse pas.
  3. Héritez de la classe de problème et fournissez votre propre constructeur plus agréable.
  4. Sachez que passer l'argument supplémentaire n'est vraiment pas si grave.

Personnellement, je trouve que le n ° 2 est le plus simple à mettre en œuvre et le moins contraignant pour la conception. Les autres peuvent être bien, compte tenu de la situation et de ce que vous essayez de faire avec ces cours.

La conversion implicite est un dernier recours et ne semble vraiment valoir le coup que lorsque j'ai des foncteurs de style C ++ que j'essaie de créer - des objets de stratégie que je convertis implicitement en types délégués.


1

Étant donné le scénario que vous décrivez, vous pouvez penser à cela en termes d'application de fonctions partielles.

Un constructeur est une fonction (au moins en théorie; en C #, vous pouvez créer une "fonction d'usine" qui appelle le constructeur):

Func<double, Point, Flavour, Circle> MakeCircle = (r, p, f) => new Circle(r, p, f);

pour une application partielle, les éléments suivants suffiront:

public static Func<T1, T2, R> Partial<T1, T2, T3, R>(this Func<T1, T2, T3, R> func, T3 t3)
   => (t1, t2) => func(t1, t2, t3);

Vous pouvez maintenant obtenir votre constructeur qui ne nécessite que 2 paramètres:

Func<double, Point, Circle> MakeCardboardCircle = Circle.Partial(Flavours.Cardboard)

Alors maintenant, vous avez une fonction d'usine avec vos paramètres souhaités

Circle c = MakeCardboardCircle(1.0, new Point(0, 0)))

BTW, c'est clairement équivalent à l'option 2 ci-dessus, juste d'un point de vue plus fonctionnel.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.