Moi j'aurai employé un modèle simple, la solution ressemble un peu à celle de Brunni (je détaillerai après le bout de code)
public abstract class RectangleBase
{
public abstract int Width { get; }
public abstract int Height { get; }
public int GetPerimeter { return 2 * (Width + Height); }
public int GetSurface { return Width * Height; }
}
public class Rectangle : RectangleBase
{
private int width;
private int height;
public sealed int Width
{
get { return width; }
set
{
if (value < 0)
throw new ArgumentOutOfRangeException("value");
width = value;
}
}
public sealed int Height
{
get { return height; }
set
{
if (value < 0)
throw new ArgumentOutOfRangeException("value");
height = value;
}
}
}
public class Square : RectangleBase
{
private int size;
public sealed int Width
{
get { return size; }
set
{
if (value < 0)
throw new ArgumentOutOfRangeException("value");
size = value;
}
}
public sealed int Height
{
get { return size; }
set { Width = value; }
}
}
Rien que pour ça y'a plein de variantes et je n'aurai probablement même pas utilisé ce modèle, car celui à utiliser précisément du contexte.
Ensuite, je reproche un truc à cette question, c'est qu'elle te force à penser héritage. Mais en fait si on y réfléchit bien c'est une mauvaise solution. Dans sa nature, un carré est un type spécial de rectangle, donc on pense héritage.
Mais avec de l'héritage, un rectangle peut également être un carré sans que celui-ci soit de classe carré (ça peut être désirable pour certains cas quand même hein)… Rien que ça moi, ça m'incite à penser que la meilleure solution pour représenter un rectangle ou un carré, c'est juste de ne pas avoir de classe carré. Si on y réfléchit bien ce que ça veut dire, c'est qu'on veut un rectangle qui soit contraint à être un carré, ou un rectangle qui ne soit pas contraint.
En fait la « solution parfaite » je pense, est celle d'un rectangle avec contraintes, ce qui colle plus à ce qu'on veut en vrai: De base, un rectangle est un rectangle, mais on peut lui appliquer une contrainte (je vous laisse réfléchir à la façon de faire, avec un champ booléen isSquare, ou bien avec une objet externe dérivé de IRectangleConsraint…), et ce éventuellement de manière dynamique (appliquer et annuler la contrainte à la volée), mais en aucun cas on n'a de type Square ou autre…
Il me semble que cette approche est plus proche de la réalité que les autres, mais bon, à vous de voir. (Je trouve _vraiment_ le modèle d'héritage non adapté pour cette situation)
À mon avis vous cherchez tous des solutions plus moisies les unes que les autres (cf
./1042 …) pour quelque chose qui n'en mérite pas tant

(PS: j'aime quand même bien le modèle que j'ai proposé, je résout pas mal de problèmes avec ce modèle simple… Juste pas ce cas précis.)
[EDIT] J'avais oublié de modifier le copier coller pour la surface… vous n'avez rien vu…
