Digamos que tengo una versión gratuita y de pago de la aplicación. La versión paga es un superconjunto de la versión gratuita con respecto a las características disponibles para los usuarios, lo que significa que la versión paga tendrá todas las características de la aplicación gratuita más un extra.
¿Existe un patrón para alternar la disponibilidad de funciones en función de un indicador que se carga al inicio (por ejemplo, gratis / pago)?
No me gusta la idea de tener los siguientes bloques de código en todas partes:
if(isFreeVersion){
// ...
} else {
// ...
}
Tener 2 ramas git separadas para cada versión no es una opción porque significaría mantener 2 (o más) fuentes de código, parece poco práctico en general y se discute más aquí: Mantener dos versiones de software separadas de la misma base de código en Control de versiones .
¿Hay alguna manera de hacer esto, sin dejar de tener una sola base de código y sin ensuciar el código con declaraciones condicionales que verifican el indicador de pago / gratis?
Estoy seguro de que esto se discutió muchas veces antes y estoy seguro de que hay algunos patrones para abordar este problema, pero simplemente no puedo encontrarlo.
Usamos Android / Java.
fuente
if
controles para ocultar los controles de las características prohibidas o tener un cuadro de diálogo emergente para cuando el usuario intenta hacer lo que no tiene permitido. Espero encontrar una manera de evitar muchos condicionales en el códigoRespuestas:
Un like condicional
if(isFreeVersion)
debería ocurrir solo una vez en el código. Este no es un patrón, pero estoy seguro de que ya conoce su nombre: se llama el principio DRY . Tener un código como "if(isFreeVersion)
" en más de un lugar en su código significa que repitió esta línea / la lógica en ella, lo que significa que debe ser refactorizada para evitar la repetición."
if(isFreeVersion)
" debe usarse para configurar una lista de opciones de configuración interna para diferentes funciones. El código resultante podría verse así:Esto asigna su único indicador "isFreeVersion" a diferentes características . Tenga en cuenta que puede decidir aquí si prefiere utilizar indicadores booleanos individuales para características individuales, o usar algún otro tipo de parámetros, por ejemplo, diferentes objetos de estrategia con una interfaz común, si el control de características requiere una parametrización más compleja.
Ahora tiene el control de lo que está en la versión gratuita y de la versión paga en un solo lugar, lo que hace que el mantenimiento de esta lógica sea bastante simple. Todavía tendrá que tener cuidado para no tener su código abarrotado de muchas
if(feature1Enabled)
declaraciones (siguiendo el principio DRY), pero ahora el mantenimiento de estas comprobaciones ya no es tan doloroso. Por ejemplo, tiene un control mucho mejor de lo que necesita cambiar cuando desea que una función paga existente sea gratuita (o viceversa).Finalmente, echemos un vistazo al artículo del blog de Fowler sobre las funciones de alternancia , donde habla sobre los puntos de entrada / función de funciones. Permítanme citar un punto central:
Por lo tanto, como estrategia general, concéntrese en la interfaz de usuario y restrinja sus controles al número mínimo de puntos necesarios para que una determinada característica aparezca o desaparezca. Eso debería mantener limpia su base de código, sin ningún desorden innecesario.
fuente
isFreeVersion
a determinados parámetros de la operación elimina la mayor parte del dolor de esas pruebas - que realmente empezará a tener sentido y no producen un lío de mantenimiento más.Si no le gustan los
if/else
bloques, puede refactorizarlos para usar la herencia (consulte Reemplazar condicional por polimorfismo del libro Refactorización de Marin Fowler ). Esto sería:Haz que sea un poco más simple razonar sobre tu código.
Permitir tener dos clases, una para la versión gratuita y la otra para la versión paga, que a su vez enviaría las llamadas a otras clases, asegurando que la distinción entre versiones gratuitas y pagas se limita a dos clases (tres contando el clase base).
Facilite, más adelante, agregar otras formas de su software, como una variante barata o una versión premium. Simplemente agregará otra clase y la declarará una vez en su código, y sabrá que toda la base de código seguirá funcionando como se esperaba.
fuente
Me parece que su pregunta podría resolverse bastante bien aplicando el Patrón de alternancia de funciones .
Como suele ser el caso, Pete Hodgson explicó en un artículo todos los escenarios que podría enfrentar al aplicar este patrón, mucho mejor de lo que yo podría hacer.
También hay algunas bibliotecas que admiten este patrón. Tenía experiencia trabajando con FF4J en Java, pero supongo que si escribe:
... en cualquier motor de búsqueda obtendrás varias soluciones.
fuente
Hay más de una forma de lograr esto. La forma simple y directa es utilizar el Patrón de alternancia de funciones que se proporciona en tantos artículos. El siguiente enfoque tiene que ver con el diseño de características conectables. Tanto Android como IOS tienen pagos en la aplicación. Junto con ese pago, existe la posibilidad de una descarga.
Cuando observa Servlets, JAMES Mailets e incluso complementos IDE, todos utilizan el concepto de una arquitectura de complemento:
Lo que esto también le permite es tener la oportunidad de tener diferentes clases de características disponibles para diferentes audiencias. Los usuarios solo tienen las funciones que pagaron.
El código de su aplicación se mantiene como una base de código, y su complemento es una base de código separada, pero solo incluye las partes que son relevantes para el complemento. La aplicación sabe cómo manejar los complementos cuando están presentes, y el complemento solo sabe cómo interactuar con la interfaz.
fuente