Digamos que eu tenho uma versão gratuita e paga do aplicativo. A versão paga é um superconjunto da versão gratuita referente aos recursos disponíveis para os usuários, o que significa que a versão paga terá todos os recursos do aplicativo gratuito e mais extras.
Existe um padrão para alternar a disponibilidade do recurso com base em um sinalizador carregado na inicialização (por exemplo, gratuito / pago)?
Não gosto da ideia de ter os seguintes blocos de código em todos os lugares:
if(isFreeVersion){
// ...
} else {
// ...
}
Ter duas ramificações git separadas para cada versão não é uma opção, porque isso significaria manter 2 (ou mais) fontes de código, parece impraticável em geral e é discutido mais aqui: Manutenção de duas versões de software separadas da mesma base de código no controle de versão .
Existe uma maneira de fazer isso, apesar de ainda ter uma única base de código e não encher o código com instruções condicionais que verificam o sinalizador de pagamento gratuito?
Tenho certeza de que isso foi discutido várias vezes antes e tenho certeza de que existem alguns padrões para abordar esse problema, mas simplesmente não consigo encontrá-lo.
Usamos Android / Java.
fonte
if
verificações para ocultar controles de recursos proibidos ou ter uma caixa de diálogo pop-up para quando o usuário tenta fazer o que não tem permissão. Estou esperando para encontrar uma maneira de evitar muitos condicionais no códigoRespostas:
Um like condicional
if(isFreeVersion)
deve ocorrer apenas uma vez no código. Este não é um padrão, mas tenho certeza que você já sabe o nome para ele: é chamado de princípio DRY . Ter código como "if(isFreeVersion)
" em mais de um lugar no seu código significa que você repetiu essa linha / a lógica nela, o que significa que deve ser refatorado para evitar a repetição."
if(isFreeVersion)
" deve ser usado para configurar uma lista de opções de configuração interna para diferentes recursos. O código resultante pode ficar assim:Isso mapeia seu sinalizador "isFreeVersion" para diferentes recursos . Observe que você pode decidir aqui se preferir usar sinalizadores booleanos individuais para recursos individuais ou usar algum tipo de outros parâmetros, por exemplo, diferentes objetos de estratégia com uma interface comum, se o controle de recurso exigir uma parametrização mais complexa.
Agora você tem o controle do que está na versão gratuita e do que está na versão paga em um só lugar, o que simplifica bastante a manutenção dessa lógica. Você ainda terá que ter cuidado para não ter seu código confuso com muitas
if(feature1Enabled)
instruções (seguindo o princípio DRY), mas agora a manutenção dessas verificações não é mais tão dolorosa. Por exemplo, você tem um controle muito melhor do que precisa alterar quando deseja liberar um recurso pago existente (ou vice-versa).Finalmente, vamos dar uma olhada no artigo do blog de Fowler sobre alternância de recursos , onde ele fala sobre pontos de entrada / alternância de recursos. Permitam-me citar um ponto central:
Portanto, como estratégia geral, concentre-se na interface do usuário e restrinja suas verificações ao número mínimo de pontos necessários para que um determinado recurso apareça ou desapareça. Isso deve manter sua base de códigos limpa, sem qualquer confusão desnecessária.
fonte
isFreeVersion
a específicas parâmetros recurso elimina a maioria da dor desses testes - eles vão realmente começar a fazer sentido e não produzem uma bagunça manutenção mais.Se você não gosta de
if/else
blocos, pode refatorá-los para usar herança (consulte Substituir condicional por polimorfismo no livro Refatoração de Marin Fowler ). Isso seria:Simplifique um pouco o raciocínio sobre seu código.
Torne possível ter duas classes, uma para a versão gratuita e a outra para a versão paga, que, por sua vez, despachariam as chamadas para outras classes, garantindo que a distinção entre versões gratuitas e pagas seja limitada a duas classes (três contando o classe base).
Facilite, posteriormente, adicionar outras formas do seu software, como uma variante barata ou uma versão premium. Você apenas adicionará outra classe e a declarará uma vez no seu código, e saberá que toda a base de códigos ainda funcionaria conforme o esperado.
fonte
Parece-me que sua pergunta poderia ser resolvida muito bem aplicando o Padrão de alternância de recursos .
Como é frequentemente o caso, Pete Hodgson explicou em um artigo todos os cenários que você poderia enfrentar ao aplicar esse padrão, muito melhor do que eu poderia fazer.
Existem também algumas bibliotecas que suportam esse padrão. Eu tinha experiência em trabalhar com FF4J em Java, mas acho que se você digitar:
... em qualquer mecanismo de pesquisa, você terá várias soluções.
fonte
Há mais de uma maneira de conseguir isso. A maneira simples e direta é usar o Padrão de alternância de recursos, fornecido em muitos artigos. A próxima abordagem tem a ver com o design de recursos plugáveis. O Android e o IOS têm pagamentos no aplicativo. Junto com esse pagamento está o potencial para um download.
Quando você olha Servlets, JAMES Mailets e até plugins IDE, todos usam o conceito de arquitetura de plug-in:
O que isso também permite é a oportunidade de ter diferentes classes de recursos disponíveis para diferentes públicos. Os usuários têm apenas os recursos pelos quais pagaram.
O código do aplicativo é mantido como uma base de código e o plug-in é uma base de código separada - mas inclui apenas as partes relevantes para o plug-in. O aplicativo sabe como lidar com plug-ins quando eles estão presentes, e o plug-in sabe apenas como interagir com a interface.
fonte