1
votes

Gestion de la hiérarchie d'héritage en raison du principe ouvert-fermé

Lorsque j'essaie de suivre le principe ouvert-fermé (OCP) a>, après le nombre de cas d'utilisation implémentés, je me retrouve toujours avec une hiérarchie de classes héritées. Cela se produit généralement avec les ViewModels dans la structure MVVM, car ils sont beaucoup modifiés. Par exemple (C #, mais pourrait être n'importe quel autre langage orienté classe):

internal class MyAwesomeViewModel
{
    public int IntProperty { get; }
    public bool BoolProperty { get; }
    public double DoubleProperty { get; }
    public string Property1 { get; set; }
    public string Property2 { get; set; }
    public ICommand Command1 { get; }
    public ICommand Command2;

    public MyAwesomeViewModelWithBunchNewProperties(IDependency1 dependency1, IDependency2 dependency2)
    {
        _dependency1 = dependency1;
        _dependency2 = dependency2;
        Command1 = new DelegateCommand(...);
        Command2 = new DelegateCommand(...);
    }
}

Le problème est que lorsqu'il s'agit de la profondeur d'héritage de 4 niveaux et plus, cela devient très compliqué et difficile à lire. De plus, je rencontre toujours un problème de dénomination, qui est un signal de mauvaise composition (comme MainWindowViewModel , puis MainWindowViewModelCloseCommand , puis MainWindowViewModelUserRelatedProperties et ainsi de suite).

Puisque seule la dernière classe dérivée est utilisée ( MyAwesomeViewModelWithBunchNewProperties dans l'exemple ci-dessus), je considère parfois d'écraser tout l'héritage avant la publication ou tout autre jalon important en 1 classe, comme ceci:

internal class MyAwesomeViewModel
{
    private IDependency1 _dependency1;

    public string Property1 { get; set; }
    public ICommand Command1 { get; }

    public MyAwesomeViewModel(IDependency1 dependency1)
    {
        _dependency1 = dependency1;
        Command1 = new DelegateCommand(...);
    }
}

internal class MyAwesomeViewModelWithAnotherProperty: MyAwesomeViewModel
{
    public string Property2 { get; set; }

    public MyAwesomeViewModelWithAnotherProperty(IDependency1 dependency1)
        :base(dependency1)
    {
    }
}

internal class MyAwesomeViewModelWithNewCommandAndDependency: MyAwesomeViewModelWithAnotherProperty
{
    private IDependency2 _dependency2;

    public ICommand Command2;

    public MyAwesomeViewModelWithNewCommandAndDependency(IDependency1 dependency1, IDependency2 dependency2)
    : base(dependency1)
    {
        _dependency2 = dependency2;
        Command2 = new DelegateCommand(...);
    }
}

internal class MyAwesomeViewModelWithBunchNewProperties : MyAwesomeViewModelWithNewCommandAndDependency
{
    public int IntProperty { get; }
    public bool BoolProperty { get; }
    public double DoubleProperty { get; }

    public MyAwesomeViewModelWithBunchNewProperties(IDependency1 dependency1, IDependency2 dependency2)
    : base(dependency1, dependency2)
    {
    }
}

Mais cela pourrait enfreindre le principe de responsabilité unique (SRP) et conduire à une très grande SuperClasse.

La question : comment faire face à beaucoup de problème d'héritage? Ou ce n'est pas du tout un problème et c'est bien d'avoir ce type de structure de classes?


2 commentaires

Restez fidèle au SOLID dans votre domaine principal là où cela compte. Avez-vous vraiment besoin d'un code OO de premier ordre dans le ViewModel, ou de tout autre élément lié à la vue? On pourrait argumenter, mais pas pour moi à coup sûr. Je teste très soigneusement le domaine principal, mais pas le modèle de vue. Celui-ci que je couvre avec des tests E2E. J'essaie toujours de m'en tenir à certains principes, comme le DIP et le SRP.


N'oubliez pas d'accepter une réponse qui vous a le plus aidé :). Je suis également disponible pour clarifier davantage si vous avez besoin d'aide.


3 Réponses :


0
votes

Afin de faire fonctionner OCP pour vous, vous devez identifier le comportement dont vos clients ont besoin. Ces connaissances peuvent être utilisées pour créer une ou plusieurs interfaces que vos classes ViewModel implémentent ensuite. Pour éviter votre hiérarchie d'héritage, vous pouvez alors préférer la composition pour structurer vos ViewModels de la même manière


0 commentaires

0
votes

Les principes SOLID sont des idées / directives pour vous aider à trouver de meilleures solutions. Il n'y a rien intrinsèquement gagné à suivre ces principes.

La stratégie d'héritage publiée ici ne fonctionne pas bien. Il n'accomplit rien et provoque la confusion et plus de travail. Ce n’est pas une bonne façon de procéder.

Mais cela pourrait enfreindre le principe de responsabilité unique (SRP) et conduire à une très grande SuperClasse.

Le SRP est très vague quant à ce qu'est une "responsabilité unique". Vous pouvez définir cela aussi étroit ou large que vous le souhaitez. Encore une fois, le principe est juste là pour vous guider et vous faire réfléchir à ne pas mélanger inutilement des choses qui devraient être séparées.

Ici, vous pouvez dire "La responsabilité de cette classe est d'être le modèle pour les données liant la vue."

SuperClasse

La même chose. C'est juste une ligne directrice. On ne peut jamais dire "une classe ne peut avoir que N membres au maximum". Ce conseil est faux pour tout N car N est sensible au contexte.


0 commentaires

1
votes

Composition sur héritage!

Souvent, les développeurs regardent des principes comme SOLID et oublient le principe de base de la composition par rapport à l'héritage.

La première chose à retenir est que l'héritage vous lie étroitement à la classe de base. Cela conduit à des problèmes tels que les legs refusés (enfreignant le principe de substitution de Liskov).

Lorsque nous parlons de classes en POO, nous définissons un comportement associé à des données, pas à des objets. Lorsque nous modélisons le problème en fonction du comportement qu'il tente d'obtenir, nous pouvons obtenir de petits blocs de construction .

Vous pouvez définir le comportement de base de MyAwesomeViewModel en petites classes auxquelles vous pouvez vous référer dans vos autres classes. De cette façon, vous pouvez facilement composer des objets tels que MyAwesomeViewModelWithBunchNewProperties .

En ce qui concerne le principe de responsabilité unique, c'est un principe très mal compris. SRP déclare que les comportements qui vivent ensemble doivent changer ensemble. Cela signifie qu'un seul ensemble de comportements qui dépendent les uns des autres et qui changeront ensemble appartiennent à la même classe.

En ce qui concerne votre scénario spécifique, les modèles de vue peuvent souvent ne pas bénéficier de la composition ou de l'héritage. Les modèles de vue sont des objets de transfert de données (DTO), ils ne capturent pas le comportement. La duplication de code ici peut être très facilement négligée \ acceptable. Si la duplication de code pose un problème dans vos modèles de vue, composez-les simplement à partir d'autres DTO


0 commentaires