【发布时间】:2013-12-11 16:58:29
【问题描述】:
在使用 Selenium WebDriver 的过程中,我注意到他们的 API 中有一种模式以及他们的类层次结构。
api是这样设置的:
Interface A {
void doAStuff();
}
Interface B {
void doBStuff();
}
Interface C {
void doCStuff();
}
Class X implements A, B, C {
...
}
Class Y implements A, B, C {
...
}
Class Z implements A, B, C {
...
}
实现如下所示:
public void doStuffWithImplementationsOfA(A a) {
a.doAStuff();
B b = (B) a;
b.doBStuff();
C c = (C) a;
c.doCStuff();
}
public static void main(String[] args) {
A a = new X();
doStuffWithImplementationsOfA(a);
}
如您所见,接口 A、B 和 C 根本不相互扩展,但在 API 中,A 的所有实现也实现了 B 和 C,因此允许交叉转换。具体来说,在 Selenium 中,WebDriver 的所有实现(如 FirefoxDriver 和 ChromeDriver)还实现了其他几个常见的不相关接口(HasInputDevices、JavascriptExecutor 等);同样,WebElement 的所有实现都实现了其他常见的不相关接口(如可定位)。这不仅允许,而且需要在接口之间进行交叉转换以访问每个实现中的各种方法。
我的问题,分为三个部分:
- 这种层次结构是否符合设计模式?
- 如果有,它有名字吗?
- 以这种方式设计 API 有哪些优点/缺点(而不是仅仅让 C 扩展 B,B 扩展 A)?
编辑:这是 WebDriver API 层次结构的图表(并非详尽无遗)。
【问题讨论】:
-
它可能有一个名字,但假设
AB和C不相互依赖,不要强制它。输入每个接口名称的额外字符对于它提供的简洁代码是一个很好的权衡。 (仅仅因为我有实现Iterable和Serializable的东西并不意味着我应该做一个扩展两者的东西) -
这看起来很可怕。我希望我永远不必这样做……永远。
-
@MrTi “额外的字符......对于干净的代码来说是一个很好的权衡”:这似乎是这样设计 API 的一个很好的理由;它在 API 中提供了凝聚力。交叉铸造本身似乎是一个缺点,所以我想知道这种设计是否还有其他好处,或者在这种情况下是否可以阐述内聚的好处?
-
如果我只想扩展其中的 1 或 2 个,而不是全部三个。例如,不强制驱动程序允许截取屏幕截图。 (他们可以发布一个不截屏的驱动程序,并在未来实现一个待办事项)
-
@MrTi 很好的观察。我看到 RemoteWebDriver 和 HTMLUnitWebDriver 没有实现 TakesScreenshot。我在我的问题中附上了一张图表来说明这一点。
标签: java design-patterns interface casting selenium-webdriver