Il y a deux façons dans lequel les classes de base abstraites sont utilisés.
Vous êtes spécialisé votre objet abstrait, mais tous les clients peuvent utiliser la classe dérivée par le biais de son interface de base.
Vous utilisez une classe de base abstraite pour le facteur de répétition à l'intérieur des objets dans votre dessin, et des clients utilisent des implémentations concrètes par le biais de leurs propres interfaces.!
Solution 1 - Modèle De Stratégie
Si vous avez de la première situation, alors vous avez réellement besoin d'une interface définie par les méthodes virtuelles dans la classe abstraite que vos classes dérivées sont à mettre en œuvre.
Vous devriez envisager d'en faire une véritable interface, changer votre classe abstraite pour être concret, et de prendre une instance de cette interface dans son constructeur. Vos classes dérivées deviennent alors les implémentations de cette nouvelle interface.
Cela signifie que vous pouvez maintenant tester vos précédemment classe abstraite à l'aide d'une maquette instance de la nouvelle interface, et chaque nouvelle mise en œuvre, par le biais de la désormais interface publique. Tout est simple et vérifiable.
Solution 2
Si vous avez la seconde situation, votre classe abstraite est une classe d'assistance.
Jetez un oeil à la fonctionnalité qu'il contient. Voir si elle peut être poussée sur les objets qui sont manipulés afin de minimiser cette duplication. Si vous avez encore quelque chose à gauche, regard à en faire une classe helper que votre mise en œuvre concrète de prendre dans leur constructeur et de suppression de ses de la classe de base.
Cela entraîne encore pour les classes de béton, qui sont simples et facilement vérifiables.
En Règle générale
Faveur réseau complexe de simples objets sur un simple réseau d'objets complexes.
La clé extensible de code de tests est petits blocs de construction et indépendant de câblage.
Mise à jour : Comment gérer les mélanges des deux?
Il est possible d'avoir une classe de base réaliser les deux de ces rôles... c'est à dire: il a une interface publique, et a protégé méthodes d'aide. Si c'est le cas, alors vous pouvez factoriser l'aide de méthodes dans une classe (scénario 2), et de convertir de l'arbre d'héritage dans un modèle de stratégie.
Si vous trouvez que vous avez certaines méthodes de votre classe de base met en œuvre directement et d'autres sont virtuels, alors vous pouvez toujours convertir l'arbre d'héritage dans un modèle de stratégie, mais je voudrais aussi le prendre comme un bon indicateur que les responsabilités ne sont pas correctement alignés, et peut-être besoin d'un refactoring.
Mise à jour 2 : les Classes Abstraites comme d'un tremplin (2014/06/12)
J'ai eu une situation à l'autre jour où j'ai utilisé abstrait, donc j'aimerais explorer pourquoi.
Nous avons un format standard pour nos fichiers de configuration. Cet outil a 3 fichiers de configuration de tous dans ce format. Je voulais une classe fortement typée pour chaque paramètre du fichier de sorte, par le biais de l'injection de dépendance, une classe pourrait demander pour les réglages, il se souciait.
Je l'ai fait en ayant une classe de base abstraite qui sait comment analyser les paramètres des formats de fichiers et les classes dérivées qui a exposé ces mêmes méthodes, mais encapsulée l'emplacement du fichier de paramètres.
Je pourrais avoir écrit "un SettingsFileParser" que les 3 classes enveloppé, puis délégué par le biais de la classe de base afin d'exposer les méthodes d'accès aux données. J'ai choisi de ne pas le faire encore car elle conduirait à 3 classes dérivées avec plus de délégation de code en eux qu'autre chose.
Cependant... que ce code évolue, et les consommateurs de chacun de ces paramètres de classes deviennent plus claires. Chacun des paramètres utilisateurs demander de certains paramètres et de les transformer en quelque sorte (comme les paramètres de texte, ils peuvent enveloppez-les dans des objets, de les convertir en nombres, etc.). Comme cela arrive, je vais commencer à extraire de cette logique dans la manipulation des données méthodes et les pousser à l'arrière sur la fortement typé paramètres de classes. Cela conduira à un plus haut niveau de l'interface pour chaque jeu de paramètres, c'est finalement pas plus au courant il s'agit de "paramètres".
À ce stade, la fortement typé paramètres de classes n'aurez plus besoin de le "getter" méthodes qui exposent le sous-jacent "paramètres" de la mise en œuvre.
À ce point, je ne veux plus de leur interface publique pour inclure les paramètres des méthodes accesseur; je vais donc changer cette classe d'encapsuler un des paramètres de l'analyseur de classe au lieu de tirer.
La classe Abstraite est donc: pour moi un moyen d'éviter de délégation de code pour le moment, et d'un marqueur dans le code pour me rappeler de changer la conception plus tard. J'ai peut-être jamais, de sorte qu'il peut vivre un bon moment... seul le code peut dire.
J'ai trouver que cela est vrai avec une règle... comme "pas de méthodes statiques" ou "pas de méthodes privées". Ils indiquent une odeur dans le code... et c'est bon. Il vous permet de rester à la recherche de l'abstraction que vous avez manqué... et vous permet d'effectuer sur la fourniture de valeur à votre client dans le temps de le dire.
J'imagine que les règles comme celle de la définition d'un paysage, où maintenable code de vie dans les vallées. Lorsque vous ajoutez de nouveaux comportements, c'est comme la pluie d'atterrissage sur votre code. Au départ, vous la mettre là où il atterrit.. alors vous refactoriser le code pour autoriser les forces de la bonne conception de pousser le comportement autour jusqu'à ce que tout se termine dans les vallées.