2016-10-11 1 views
1

Est-ce une pratique bonne/acceptable de dériver de l'objet uniquement pour masquer toute la logique liée à la création de cet objet? .Utilisation de l'héritage pour l'encapsulation de la composition

Par exemple (bien que n'étant pas un exemple parfait) j'ai une classe Scene. Je veux l'initialiser avec certaines entités, certains systèmes, définir la couleur d'arrière-plan et ainsi de suite. Je pourrais créer Factory pour cela mais j'ai choisi de faire tout ça dans le constructeur de la classe dérivée.

Au lieu de cela:

var scene = new Scene(); 
scene.Systems (new ColisionSystem); 
scene.Systems (new MovementSystem); 
scene.SceneGraph = new MyCustomSceneGraph(); 

Je fais ceci:

class MyScene : Scene 
{ 
    void MyScene(SceneGraph sceneGraph) 
    { 
     this.Systems (new ColisionSystem); 
     this.Systems (new MovementSystem); 

     this.SceneGraph = sceneGraph; 
    } 
} 

var scene = new MyScene(new MyCustomSceneGraph()); 

Je me cache tout ce genre de choses de la création dans le constructeur et comme un bonus, je suis arrivé fichier séparé pour chaque scène je vais créer .

Dans l'autre sens. Si jamais je crée un éditeur de scène, cela peut poser problème. Parce que dans ce cas, le client de l'objet scène devrait être responsable de la préparation de la scène, et non la scène elle-même.

Est-ce une pratique acceptable ou est-ce que cela constitue une violation de la SRP?

+3

Cela ne me semble pas être un très bon usage de l'héritage. Pourquoi ne pas simplement créer une méthode statique pour faire tout cela pour vous? Je ne vois aucun avantage à utiliser l'héritage ici, car vous ne spécialisez aucun comportement ou ajoutez plus d'état. –

+0

En général, vous devriez préférer [Composition over Inheritance] (https://en.wikipedia.org/wiki/Composition_over_inheritance). – Steven

+1

@Steven La structure des classes d'OP suggère qu'il préfère déjà la composition à l'héritage.Je pense que sa question porte sur la validité de l'utilisation de l'héritage pour la composition * configure *, ce qui, à mon avis, a des implications négatives. – dasblinkenlight

Répondre

1

Vous avez identifié le problème exact avec l'approche sous-classe-par-composition: il est lié à la compilation, ce qui rend la composition de l'exécution beaucoup plus difficile. En outre, la logique de composition codée en dur dans le constructeur de sous-classe exige que vous recompiliez chaque fois que vous devez modifier la logique, même si la seule chose qui est modifiée est le graphe d'instance d'exécution dans votre système.

Vous pouvez répondre à l'exigence de composition de vos objets lors de l'exécution en ajoutant une classe décrivant les connexions sans les créer, puis en ajoutant un constructeur qui prend les descriptions et les traite en objet Scene complet. Pour rendre ceci moins abstrait, pensez à un fichier de configuration dans votre format lisible par l'homme préféré, par ex.

{"Systems":["ColisionSystem", "MovementSystem"], "SceneGraph":"MyCustomSceneGraph"} 

et une interface qui vous permet d'accéder à ces données:

interface SceneConfiguration { 
    IList<String> Systems {get;} 
    String SceneGraph {get;} 
    ... // More configuration items 
} 

Considérons maintenant un analyseur qui produit une instance de SceneConfiguration de cette représentation, et un constructeur de Scene qui prend SceneConfiguration comme argument: Cet arrangement vous permet de "coder en douceur" la composition à travers un fichier de configuration. Cette approche fonctionne également avec les éditeurs de scènes: votre éditeur de scène crée des instances de SceneConfiguration, tandis que Scene conserve le contrôle de sa création.