虽然我不确定我是否为它选择了正确的名称,但是任何在大型项目上工作的人都可能已经看到了它:一些布尔返回函数随着每个小特征的交互而变得臃肿。最终,曾经简单的一两个变量检查变为:
public boolean showFavoritesTool(UserData userData){
if(currentPage.isPremiumPage())
{
return true;
}
if(!userData.isLoggedIn())
{
return false;
}
if(userData.isMember())
{
return userData.getPreferences().isFavoritesTurnedOn();
}
if(getUrlParams()["showFavorites"])
{
return getUrlParams()["showFavorites"]
}
return false;
}
编辑:让我澄清一下,这只是像这样的函数的早期例子。在某些时候,随着新功能发展到至少两倍这个尺寸,它会增长。我正在看的功能促使这个问题至少有15个变量,其中一些是嵌套的。这段代码可能看起来很简单,但是在添加新变量时它不会保留。
每次添加新功能时,都会在flag功能中输入另一个条目。它们通常不会重叠,但是当它们发生时,你可以确定没有人想过会发生什么。不久之后,这些功能难以解释。
这有更清洁的解决方案吗?此外,如果更清洁的解决方案涉及更多的架构,何时实现它?只要添加第二个变量?还是有一些突破点?
答案 0 :(得分:3)
我会以更有意识和可理解的形式重写它。这需要一些关心,因为早期返回,(双重)否定等通常会掩盖行为,并且很容易引入错误。
public boolean showFavoritesTool(UserData userData)
{
return currentPage.isPremiumPage()
|| userData.isLoggedIn() && userData.isMember() && userData.getPreferences().isFavoritesTurnedOn()
|| userData.isLoggedIn() && getUrlParams()["showFavorites"];
}
如果逻辑变得非常复杂,它有助于引入一些中间变量。
public boolean showFavoritesTool(UserData userData)
{
var isPremiumPage = currentPage.isPremiumPage();
var isLoggedIn = userData.isLoggedIn();
var isMemberAndHasFavoritesTurnedOn = userData.isMember() && userData.getPreferences().isFavoritesTurnedOn();
var urlIndicatesShowFavorites = getUrlParams()["showFavorites"];
return isPremiumPage
|| isLoggedIn && isMemberAndHasFavoritesTurnedOn
|| isLoggedIn && urlIndicatesShowFavorites;
}
在这个例子中,它有点多,但你明白了。将中间变量的含义与业务或技术要求对齐通常是个好主意。
答案 1 :(得分:3)
您的问题相当笼统,很难理解其范围,但我会尝试提供一些有希望回答它的见解。
每次添加新功能时,都会在flag功能中输入另一个条目。他们通常不会重叠,但是当他们这样做时,你可以确定没有人想过应该发生什么
这是一个糟糕的计划和设计的副作用。 Code should be closed for modification, but open to extension
如前所述,Yuval Itzchakov提到了未来的设计,一个包含抽象showFavouritesTool()
方法的接口,每个用户类根据每个类要求覆盖它将提供更大的灵活性,并坚持开放/封闭原则。不幸的是,由于提供的信息有限,很难创建一个适合您问题的示例。
很明显,会有多个布尔表达式需要检查的情况。为什么不使用简洁的声明来简化方法。
例如:
public boolean showFavoritesTool(UserData userData){
return currentPage.isPremiumPage()
|| userData.isLoggedIn() && userData.isMember() && userData.getPreferences().isFavoritesTurnedOn()
|| userData.isLoggedIn() && getUrlParams()["showFavorites"];
}
答案 2 :(得分:0)
如果所有验证都保留在同一个地方,则清除(例如,取出第二个if,并使其返回true,将返回值放在第三个if中,并使其返回true,与最后一个if)相同,并在"收藏夹工具"应该显示,我没有看到它的问题。
答案 3 :(得分:0)
我认为你的问题有点过于笼统,因为我并不完全理解问题的范围。我们不了解的字段有多种用途。
但总的来说,如果你试图将要公开的功能集分类到一组用户,你可以让它们都继承一个基类型,它有一个带有一个名为SetFavoriteTool的函数的抽象方法,就像这样:
public abstract class BaseData
{
public abstract bool ShowFavoriteTool();
}
public class UserData : BaseData
{
public override bool ShowFavoriteTool()
{
if ....
}
}
或者如果您更多地使用接口,您可以依赖于IFavoriteTool:
public interface IFavoriteTool
{
bool ShowFavoriteTool();
}
public class UserData : IFavoriteTool
{
public bool ShowFavoriteTool()
{
if..
}
}
然后您可以将方法更改为:
public bool ShowFavoriteTool(UserData userData)
{
var favoriteTool = (IFavoriteTool) userData;
return favoriteTool.ShowFavoriteTool();
}
这只是一个主角,因为我不太了解您正在处理的域名问题。
希望这有帮助。
答案 4 :(得分:0)
这就是所谓的"代码腐烂。"它是性能和/或可维护性降低源的过程。最终它可能降级到性能变得如此糟糕或者变得如此不可维护以至于你必须重新开始(版本2.0)
代码棒由于增量增强或错误修复而导致您的设计越来越远离原始设计。
要打击代码腐败,您需要拥有(并执行)良好的标准。有代码审查,代码审计,文档源,写单元测试等。
答案 5 :(得分:0)
我偶尔会创建自己的枚举来声明对象的状态。在这种情况下,类似于:
public enum FavoriteToolState {
IsVisible,
IsHidden
}
这样,您可以在内部方法中设置收藏夹的状态,这实际上决定了收藏夹是否是高级版,或者用户是否已登录,或者是否有其他任何选项,而不是检查每个那些方法,您可以检查当前的FavoriteToolState是否是FavoriteToolState.IsVisible。
我想,无论这种方式是否清洁都可以论证。在某些情况下我更喜欢这种方式。