函数命名,应该使用哪个抽象级别

时间:2015-06-01 15:41:47

标签: function naming-conventions naming software-design

我们在申请中有这样的用例:

If page visitor is a crawler, then redirect him to home page.

我们已经开发了两种在代码中实现它的方法:

if (isPageVisitorACrawler(visitor)) {
    return redirectToHome();
}
if (shouldRedirectVisitorToHome(visitor)) {
    return redirectToHome();
}

确定。所以我认为第一个版本的信息量更大,但是其他人说第二个版本在适应性方面更好。这意味着如果我们必须在用户必须重定向到家时添加另一个条件,那么第二个版本将更容易和更清晰。

if (isPageVisitorACrawler(visitor) || isPageVisitorBanned(visitor)) {
    return redirectToHome();
}
if (shouldRedirectVisitorToHome(visitor)) {
    return redirectToHome();
}

在这个级别上,第二个仍然是相同的。

我的问题是,我们什么时候应该将这些函数包装到更大的(更一般的)函数中,或者我们应该将它们包含在内?

我记得Bob叔叔说我们不应该在一个函数中混合抽象级别。我相信,函数应该只调用低于其抽象级别一级的函数,而shouldRedirectVisitorToHome似乎是在同一级别上,而不是在下面。

我希望我能说清楚。

3 个答案:

答案 0 :(得分:0)

我认为,就像大多数人所说的那样,由于不同的原因,在以后的日期增加重定向案例,最好选择" shouldRedirectVisitorToHome(访客)"

一旦有超过2个子案例可以达到相同的结果,我总是将函数调用包装成更通用的调用。

编辑:如果我认为将来会有更多的案例,即使是一个单独的案例,我也会有一个通用的电话

答案 1 :(得分:0)

“isPageVisitorACrawler(visitor)”与用例描述的含义更接近。但是,如果你想给函数更通用的感觉,第二个更优选。取决于你的需要。但是,如果您计划使用if和else条件充分实现 isPageVisitorACrawler 函数的基础implmenetation,则不应使用此方法的泛型实现。我猜这违反了SOLID oop原则的OCP部分。

答案 2 :(得分:0)

I'd say neither one.

isPageVisitorACrawler(visitor) makes it to specific to the "page visitor", but makes it seem it's not directly related to it.

shouldRedirectVisitorToHome(visitor) implies a specific use case.

Without knowing the specific on how you determine if the visitor is a crawler (I assume visitor has a UserAgent or IP/Host property), the most logic assumption would be to make it visitor.IsCrawler() and visitor.IsBanned() and determine the action in something like

public class Visitor 
{
    private string userAgent;
    private UserStatus status = UserStatus.Active;

    public bool IsCrawler() 
    {
        return userAgent.Contains("Google Bot");
    }

    public bool IsBanned()
    {
        return status == UserStatus.Banned;
    }
}

// In your controller
if(!security.HasAccessTo(visitor, page)) 
{
    return RedirectToHome(); 
}

// example of basic implementation of HasAccessTo
public bool HasAccessTo(Visitor visitor, Page page) 
{
    if(visitor.IsCrawler() || visitor.IsBanned())
    {
        return false;
    }

    List<GroupPermission> permissions = permissionsRepository.GetPermissions(visitor);
    foreach(GroupPermission permission in page.Groups) 
    {
        if(permissions.Contains(permission))
        {
            return true;
        }
    }

    // if no permissions were found, refuse
    return false;
}

This will also make your code easier to read and easier to reuse the logic which determines if the visitor is a crawler or banned. Every developer, even new developers who are not familiar with the project, will instantly understand the code and what it is supposed to do.

The idea behind the "Rich Domain Model" is to put as much logic that belongs to an domain entity in it as possible and make sure the domain entity can keep itself in a valid state.

All other logic, that can't be put into an rich domain model, goes into service or factory classes. This will make changes easier, as you apply it to the domain entity and only have a thin service layer instead of anemic domain models and monolithic service layer which becomes hard to maintain as your problem domain grows.