Disons que j'ai une version gratuite et payante de l'application. La version payante est un sur-ensemble de la version gratuite concernant les fonctionnalités disponibles pour les utilisateurs, ce qui signifie que la version payante aura toutes les fonctionnalités de l'application gratuite en plus.
Existe-t-il un modèle pour basculer la disponibilité des fonctionnalités en fonction d'un indicateur qui se charge au démarrage (par exemple, gratuit / payant)?
Je n'aime pas l'idée d'avoir les blocs de code suivants partout:
if(isFreeVersion){
// ...
} else {
// ...
}
Avoir 2 branches git distinctes pour chaque version n'est pas une option car cela signifierait la maintenance de 2 (ou plus) sources de code, semble peu pratique en général et est discuté plus ici: Maintenir deux versions logicielles distinctes à partir de la même base de code dans le contrôle de version .
Y a-t-il un moyen de le faire, tout en ayant une base de code unique et sans joncher le code avec des instructions conditionnelles qui vérifient l'indicateur gratuit / payant?
Je suis sûr que cela a été discuté à plusieurs reprises auparavant et je suis sûr qu'il existe des modèles pour aborder ce problème, mais je ne le trouve pas.
Nous utilisons Android / Java.
la source
if
vérifications pour masquer les contrôles des fonctionnalités interdites ou d'avoir une boîte de dialogue contextuelle lorsque l'utilisateur essaie de faire ce qu'il n'est pas autorisé à faire. J'espère trouver un moyen d'éviter de nombreuses conditions dans le codeRéponses:
Un conditionnel
if(isFreeVersion)
doit se produire une seule fois dans le code. Ce n'est pas un modèle, mais je suis sûr que vous en connaissez déjà le nom: il s'appelle le principe DRY . Avoir du code comme "if(isFreeVersion)
" à plusieurs endroits dans votre code signifie que vous avez répété cette ligne / la logique qu'elle contient, ce qui signifie qu'elle doit être refactorisée pour éviter la répétition."
if(isFreeVersion)
" doit être utilisé pour définir une liste d'options de configuration interne pour différentes fonctionnalités. Le code résultant pourrait alors ressembler à ceci:Cela met en correspondance votre indicateur "isFreeVersion" unique avec différentes fonctionnalités . Notez que vous pouvez décider ici si vous préférez utiliser des indicateurs booléens individuels pour des fonctionnalités individuelles, ou utiliser une sorte d'autres paramètres, par exemple différents objets de stratégie avec une interface commune, si le contrôle des fonctionnalités nécessite une paramétrisation plus complexe.
Maintenant, vous avez le contrôle de ce qui se trouve dans la version gratuite et de la version payante en un seul endroit, ce qui rend la maintenance de cette logique assez simple. Vous devrez toujours faire attention à ne pas avoir votre code encombré de nombreuses
if(feature1Enabled)
instructions (en suivant le principe DRY), mais maintenant la maintenance de ces vérifications n'est plus si douloureuse. Par exemple, vous avez un bien meilleur contrôle sur ce que vous devez changer lorsque vous souhaitez rendre une fonctionnalité payante existante gratuite (ou vice versa).Enfin, jetons un coup d'œil à l'article de blog de Fowler sur les basculements de fonctionnalités , où il parle de points d'entrée / de basculement de fonctionnalités. Permettez-moi de citer un point central:
Donc, en tant que stratégie globale, concentrez-vous sur l' interface utilisateur et limitez vos vérifications au nombre minimal de points requis pour faire apparaître ou disparaître une certaine fonctionnalité. Cela devrait garder votre base de code propre, sans encombrement inutile.
la source
isFreeVersion
à spécifiques paramètres de fonction supprime la plupart de la douleur de ces tests - ils réellement commencer à faire sens et ne produisent pas un gâchis d'entretien plus.Si vous n'aimez pas les
if/else
blocs, vous pouvez les refactoriser pour utiliser l'héritage (voir Remplacer le conditionnel par le polymorphisme du livre de refactorisation de Marin Fowler ). Cela:Faites un peu plus simple de raisonner sur votre code.
Permettre d'avoir deux classes, une pour la version gratuite et l'autre pour la version payante, qui à leur tour répartiraient les appels vers d'autres classes, en veillant à ce que la distinction entre versions gratuite et payante soit limitée à deux classes (trois comptant le classe de base).
Rendez-vous facile, plus tard, pour ajouter d'autres formes de votre logiciel, comme une variante bon marché ou une version premium. Vous allez simplement ajouter une autre classe et la déclarer une fois dans votre code, et vous saurez que la base de code entière fonctionnerait toujours comme prévu.
la source
Il me semble que votre question pourrait être assez bien résolue en appliquant le modèle de bascule de fonction .
Comme c'est souvent le cas, Pete Hodgson a expliqué dans un article tous les scénarios auxquels vous pourriez faire face en appliquant ce modèle, bien mieux que je pourrais le faire.
Certaines bibliothèques prennent également en charge ce modèle. J'avais de l'expérience avec FF4J en Java mais je suppose que si vous tapez:
... dans n'importe quel moteur de recherche, vous obtiendrez plusieurs solutions.
la source
Il y a plus d'une façon d'y parvenir. Le moyen simple et direct consiste à utiliser le modèle de bascule de fonctionnalité fourni dans de nombreux articles. La prochaine approche concerne la conception de fonctionnalités enfichables. Android et IOS ont tous deux des paiements intégrés. Parallèlement à ce paiement, il existe un potentiel de téléchargement.
Lorsque vous regardez les servlets, les messageries JAMES et même les plugins IDE, ils utilisent tous le concept d'une architecture de plug-in:
Cela vous permet également d'avoir la possibilité de disposer de différentes classes de fonctionnalités pour différents publics. Les utilisateurs n'ont que les fonctionnalités pour lesquelles ils ont payé.
Le code de votre application est conservé comme une seule base de code, et votre plug-in est une base de code distincte - mais inclut uniquement les parties pertinentes pour le plug-in. L'application sait comment gérer les plugins lorsqu'ils sont présents, et le plugin ne sait que comment interagir avec l'interface.
la source