我正在重构一些应用程序(scraper),我已经创建了一个单独的应用程序。有一些抓取工具,例如TwitterScraper
,FacebookScraper
等。这些名称仅用于解释问题。
假设我想要使用这些刮刀检索人员。我们可以在每个刮刀中使用不同的方式进行搜索。例如,在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)
}
}
设计它的好方法是什么?
答案 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.
}
}
但是我忘记了如何在消费者层面使用它。