2017-06-30 1 views
0

Combien de déclarations de fonctions abstraites d'une classe abstraite sont-elles trop nombreuses?Trop de fonctions abstraites - OOP Meilleures pratiques

Par exemple, pour un système de paiement fondé sur des membres:

Plusieurs modes de paiement sont pris en charge:

  • Carte de crédit
  • jeton (un paiement par carte de crédit, mais en utilisant un jeton)
  • Redirect (par exemple Paypal)
  • Manuel (admin charge manuellement l'utilisateur)

J'ai une classe abstraite PaymentMode et différents modes ci-dessus s'étendent à cette classe.

Chaque mode a sa propre logique unique des méthodes suivantes et je dois déclarer des méthodes abstraites en classe PaymentMode pour ces

// each mode has own way of validating the customer data 
validate(); 

// own logic of cleaning customer data (e.g removing/adding/updating) 
preparePaymentData(); 

// returns a string for saving in database, subclass must implement so developers plan to extend the PaymentMode abstract will be forced to return the correct value 
getModeOfPayment(); 

// each mode has its own logic when determining payment gateways to attempt 
getGatewaysToAttempt(); 

// before sending the payment to gateway, each mode has its own logic when adding specific data 
addCustomDataSpecificForGateway(); 

// check if transaction has failed, different payment modes has different logic of determining a failed transaction 
isTransactionFailed() 

Il 6 logique unique pour chaque mode, j'ai réussi à commonized la commune codes déjà et placez-le dans la classe PaymentMode.

Ce nombre peut augmenter à mesure que nous implémentons de nouvelles fonctionnalités propres à chaque mode. Dans mon esprit, je crains que si un futur développeur étend ma classe PaymentMode, il doit implémenter toutes les déclarations de fonctions abstraites.

Ainsi, un grand nombre de déclarations de fonctions abstraites indique-t-il un BAD DESIGN? Combien est trop?

Si sa mauvaise conception, puis, peut vous recommander des techniques ou des modèles de conception qui permettra de résoudre ce problème

Merci

+3

Si votre classe abstraite n'a vraiment aucune fonctionnalité implémentée, et vous ne vous attendez pas à ce qu'elle le soit, alors vous pourriez envisager d'utiliser un _interface_ à la place. Une interface serait une chose très appropriée à utiliser si vous voulez décrire _behavior_ de paiements sans spécifier exactement ce que ce comportement est. –

+0

@TimBiegeleisen merci pour votre suggestion, mais ma classe abstraite a des fonctionnalités en elle puisque ces différents modes de paiement partagent des fonctionnalités communes – Bogz

+2

Je ne vois rien de mal à avoir une poignée de méthodes abstraites. Vous pouvez également envisager d'utiliser à la fois une interface et une classe abstraite. –

Répondre

0

Il n'y a pas nombre de déclarations de fonctions abstraites qui est mauvais, bien que le grand nombre possible signifie que la conception a des défauts. Faites juste attention au principe de la responsabilité unique.

Vous avez déjà défini que vous avez 4 modes - donc je pense que vous devriez faire 4 interfaces pour chaque mode dans votre cas. Après cela, vous pouvez voir ce qui est commun pour tous les 4 et extraire l'interface de base. Vous pouvez envisager d'extraire 6 logiques uniques pour tous également des interfaces ...

1

Il est difficile de répondre sans détails, mais:

Il est évident qu'il n'y a pas de limite à des méthodes abstraites (méthodes dans les interfaces ou abstraites classes), bien que moins soit toujours plus clair et plus facile à comprendre.

Ce qui est indiquant une conception sous-optimale est cependant que vous devez modifier votre abstraction d'une méthode de paiement avec chaque nouvelle méthode de paiement. Pour moi, cela indique une abstraction défaillante. La POO ne consiste pas seulement à sortir du code commun, à éviter la duplication, mais aussi à faire des abstractions.

Ce que je regarderais en est d'une certaine façon transférer le contrôle (le réel de contrôle) au mode de paiement. Faites confiance à la méthode de paiement, déléguez la tâche d'effectuer le paiement. Ce que je veux dire par là, vous conserver contrôle quelque part, où vous demandez à la méthode de paiement de faire des parties spécifiques de son travail (avec les parties étant différentes pour différentes méthodes concrètes). Des étapes comme validate(), prepare...(). Et aussi, vous vous attendez à ce qu'il vous donne la "passerelle", donc maintenant le code en dehors de la méthode de paiement (même si c'est la superclasse) doit savoir ce que c'est, ou comment le gérer. Au lieu de faire tout cela, essayez de trouver un design qui transfère le contrôle total sur la méthode de paiement, afin qu'il puisse faire son travail sans code extérieur en supposant un ensemble d'étapes particulier.

Par exemple:

public interface PaymentMethod { 
    Receipt payFor(Bill bill); 
} 

Le PaymentMethod ici est responsable de tout faire lui-même. Rediriger l'utilisateur, enregistrer le reçu dans la base de données, tout ce qui est nécessaire. Une fois que vous vous sentez à l'aise avec cette abstraction "principale" (elle couvre tous les cas d'utilisation), vous pouvez créer des abstractions plus petites qui couvrent des détails tels que l'enregistrement dans la base de données.

Par rapport à cela: n'utilisez pas les classes parent abstraites comme un moyen de partager du code entre les classes, ce n'est pas exactement ce que l'héritage est pour. Créez des abstractions appropriées pour les différents «morceaux de code», et laissez-les être utilisés par des «plus grandes» abstractions (c'est-à-dire la composition).