在这种情况下使用什么设计选择来避免违反LSP?

时间:2013-09-17 22:18:24

标签: oop design-patterns

我正在重构一些应用程序(scraper),我已经创建了一个单独的应用程序。有一些抓取工具,例如TwitterScraperFacebookScraper等。这些名称仅用于解释问题。

假设我想要使用这些刮刀检索人员。我们可以在每个刮刀中使用不同的方式进行搜索。例如,在Facebook中,我们可以按名称,年龄等进行搜索....或者只是获取某个特定组中的所有用户,这意味着我们有两种搜索方式。 Twitter和其他人也可能发生同样的事情......

我考虑过以下设计:

public interface IScraper {
    IEnumerable<User> Search(IParameter parameters);
}

然后:

public class FacebookGroupsScraper : IScraper {
    public IEnumerable<User> Search(IParameter parameters) {
        //... search here using the group url, etc.
    }
}

public class FacebookOtherScraper : IScraper {
    public IEnumerable<User> Search(IParameter parameters) {
        //... search here using the name, age, country, or whatever...
    }
}

但我肯定违反了Liskov Substitution Principle,因为我必须在每种方法中做这样的事情:

public class FacebookOtherScraper : IScraper {
    public IEnumerable<User> Search(IParameter parameters) {
        var p = parameters as FacebookOtherParameter;

        //We can only work here with the expected parameters 
        //(FacebookOtherParameter class in this case)
    }
}

设计它的好方法是什么?

2 个答案:

答案 0 :(得分:0)

看起来实现之间的区别在于它们所采用的参数类型。

因此,为了遵守LSP,我认为最好将您的接口更改为具有单独的方法或具有单独的接口,每个接口具有采用不同类型参数的不同方法:

//... search here using the group url, etc.
public interface GroupScrapper{
     IEnumerable<User> SearchByGroup(IGroupParameter parameters...);

}
 //... search here using the name, age, country, or whatever...
public interface UserInfoScrapper{
     IEnumerable<User> SearchByInfo(IInfoParameter parameters...);

}

或作为单一界面:

public interface IScraper {
    IEnumerable<User> SearchByGroup(IGroupParameter parameters...);

    IEnumerable<User> SearchByInfo(IInfoParameter parameters...);
}

这样每个实现都将符合其中一种方法的合同。

这种方法的问题是你必须拥有一个完全已知的静态参数集。如果必须不断添加新类型的参数,那么方法和/或接口的数量将会爆炸。

答案 1 :(得分:0)

我通常会为这种情况做通用的。 (请注意下面的代码可能无法编译)

public interface IScraper<T> where T : IParameter
{
    IEnumerable<User> Search(T parameters);
}

public class FacebookParameter : IParameter{
    public string GroupUrl{ get; set; }
}

public class FacebookGroupsScraper : IScraper<FacebookParameter> {
    public IEnumerable<User> Search(FacebookParameter parameters) {
        //... search here using the group url, etc.
    }
}

但是我忘记了如何在消费者层面使用它。