对某些用户隐藏/禁用功能


10

可以说我有该应用程序的免费和付费版本。付费版本是免费版本在用户可用功能方面的超集,这意味着付费版本将具有免费应用程序的所有功能以及其他功能。

是否存在根据启动时加载的标志(例如,免费/付费)来切换功能可用性的模式?

我不喜欢到处都有以下代码块的想法:

if(isFreeVersion){
    // ...
} else {
    // ...
}

每个版本都没有2个单独的git分支是不可行的,因为这意味着要维护2个(或更多)代码源,这在一般情况下似乎不切实际,并在此处进行了更多讨论:在Version Control中从同一代码库维护两个单独的软件版本

有办法做到这一点,同时仍然只有一个代码库,并且不会用检查自由/已付费标志的条件语句来乱扔代码吗?

我敢肯定这已经被讨论过很多次了,并且我肯定有一些解决这个问题的模式,但是我只是找不到它。

我们使用Android / Java。



@gnat tnx,很高兴找到。但是我想讨论不需要单独分支和维护多个代码库的选项
TadijaBagarić18年

2
这看起来类似于具有不同的授权级别。您可能会研究该问题通常是如何解决的,该功能仅适用于某些用户/角色。
Bart van Ingen Schenau

@BartvanIngenSchenau我发现它主要是if检查以隐藏控件的禁用功能,或者在用户尝试执行其不允许执行的操作时显示弹出对话框。我希望找到一种避免代码中出现许多条件的方法
TadijaBagarić18年

2
使用多义性。您将不必再问自己有关if语句的问题,它将更加容易维护!
史蒂夫·查麦拉德

Answers:


14

有条件的like if(isFreeVersion)应该只在代码中发生一次。这不是一种模式,但是我确定您已经知道它的名称:它称为DRY原理。在代码if(isFreeVersion)中的多个位置放置类似“ ”的代码意味着您重复了这一行/其中的逻辑,这意味着应将其重构以避免重复。

if(isFreeVersion)”应用于设置不同功能的内部配置选项列表。结果代码如下所示:

 if(isFreeVersion)
 {
      feature1Enabled=false;
      feature2Enabled=false;
      maxNoOfItems=5;
      advertisingStrategy=new ShowLotsOfAdvertisementsStrategy();
      // ...
 } 
 else
 {
      feature1Enabled=true;
      feature2Enabled=true;
      maxNoOfItems=int.MaxValue; // virtually unlimited
      advertisingStrategy=new ShowMinimalAdvertisementsStrategy();
 }

这会将您的单个“ isFreeVersion”标志映射到不同的功能。请注意,如果功能控件需要更复杂的参数化,则可以在此处决定是要为单个功能使用单独的布尔标志,还是要使用某些其他参数,例如具有公共接口的不同策略对象。

现在,您可以在一处控制免费版本和付费版本中的内容,这使此逻辑的维护非常简单。您仍然必须小心,不要让您的代码被很多if(feature1Enabled)语句弄乱(遵循DRY原理),但是现在,维护此检查不再那么麻烦。例如,当您想使现有的付费功能免费时,您可以更好地控制需要更改的内容(反之亦然)。

最后,让我们看一下Fowler的博客中有关功能切换的文章,他在文章中谈到了功能进入点/切换点。让我列举一个中心点:

不要试图通过切换来保护新功能代码中的每个代码路径,而只专注于将导致用户进入那里的切入点并切换这些切入点。

因此,作为整体策略,应将重点放在用户界面上,并将检查限制在使某个功能出现或消失所需的最少点数上。那应该保持您的代码基础干净,没有任何不必要的混乱。


5
您基本上已经用FeaturexEnabled替换了IsFreeVersion,没有减少调用次数。尽管我还没有遇到这种情况,但我总是通过在菜单创建时禁用那些用户不应该看到的选项来处理类似的事情。通常,这是在创建表单时进行的,但是在准备弹出菜单时有时不得不这样做。
罗伦·佩希特尔

1
@LorenPechtel:您应该更仔细地阅读我的答案。我实际上提到了减少条件测试数量的件事,其中之一是DRY原理,其中之一是针对UI中的测试。更重要的是,将非特定标志映射isFreeVersion特定功能参数可以消除那些测试的大部分麻烦-它们实际上将变得有意义,并且不再产生维护麻烦。
布朗

9

如果您不喜欢if/else块,则可以将其重构为使用继承(请参阅Marin Fowler的《重构》一书中的“ 用多态替换条件 ”)。这个会:

  • 使推理代码稍微简单一些。

  • 使有两个类成为可能,一个用于免费版本,另一个用于付费版本,这将转而将调用分派到其他类别,从而确保免费和付费版本之间的区别仅限于两个类别(三个计算基类)。

  • 以后,可以轻松添加其他形式的软件,例如廉价版或高级版。您只需添加另一个类,然后在代码中对其进行一次声明,可以知道整个代码库仍可以按预期工作。


3
我想您可能想更清楚一点,即不需要实现继承。另一个好处是免费应用程序可以不提供高级功能就可以交付。修改Java字节码以使if条件始终为true并不是很难。
JimmyJames

6

在我看来,使用Feature Toggle Pattern可以很好地解决您的问题。

通常情况下,Pete Hodgson在一篇文章中解释了应用此模式可能遇到的所有情况,这比我能做的更好。

也有一些库支持此模式。我曾在Java中使用FF4J的经验,但我猜您是否键入:

feature toggle <whatever language you prefer>

...在任何搜索引擎中,您都会获得几种解决方案。


1

实现这一目标的方法不止一种。简单直接的方法是使用许多文章中提供的功能切换模式。下一种方法与设计可插入功能有关。Android和IOS均具有应用内付款。伴随着这笔付款,就有可能进行下载。

当您查看Servlet,JAMES Mailets甚至是IDE插件时,它们都使用了插件体系结构的概念:

  • 定义您的应用程序知道如何使用的界面。该界面需要提供一种将自身注入到应用程序导航中的方法,并将任何其他应用程序注入插件接触点。
  • 设置您的应用在启动时将读取的路径(运行时插件管理要困难得多)
  • 如果存在插件(例如Java Jar文件),则该应用要么读取清单以查找插件接口的实现,要么扫描实现该接口的类。
  • 找到该类后,将对其进行实例化,并调用适当的方法来集成新功能。

这还使您有机会将不同类别的功能提供给不同的受众。用户仅具有他们付费的功能。

您的应用程序代码被维护为一个代码库,而插件是一个单独的代码库-但仅包括与插件相关的部分。该应用程序知道如何处理存在的插件,而插件仅知道如何与界面进行交互。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.