设计模式——对象强制转换是一种好的实践吗?



面向对象的编程语言,如java, c#,…支持对象类型转换。例如,这在java中是完全有效的:

URL url = new URL("url");    
URLConnection conn = url.openConnection();
if( !conn instanceof HttpURLConnection )
  throw new Exception("not http request");
HttpURLConnection con = (HttpURLConnection) conn;   

或者我尝试过的另一个基本例子:

public class Base
{
  public void base(){}
}
public class Derived extends Base
{
  public void derived(){}
}
Base b = new Derived();
b.base();

派生类拥有所有基类拥有的方法,甚至更多。没有理由不能通过调用派生类的构造函数来创建基类。

我还看到了这个链接http://www.volantec.biz/castingObjects.htm,它解释了对象类型转换是如何在内部工作的。到目前为止,还好。

但是为什么第一个例子不使用HttpURLConnection con = new HttpURLConnection("url address")(我知道HttpURLConnection是一个抽象类)。它看起来更清晰,更简单。另一方面,当您处理接口时,对象类型转换会派上用场。另一个例子是List<Object>列表,我有时在一些课上看到。这意味着您可以保存此列表中所有可能的类。之后,如果你知道它是什么类型,你就可以把它转换成它的原始类型。如果只保存特定的类别,如List<String>, List<MyClass>,不是更清楚吗?那么使用List<Object>是好的设计实践吗?

在设计类层次结构时,您必须始终牢记Liskov替换原则(即LSP):

派生类型必须可以完全替代它们的基类型。

换句话说,要决定是否应该扩展一个类,您应该问自己,如果将新类更改为它的基类,依赖于新类的组件是否会得到很好的服务。

类型转换的问题是,如果你需要将基类对象转换为派生类对象,这意味着你违反了LSP。

如果你需要确保一个对象来自一个特定的实现,当你期待一个接口,那么肯定是你的设计有问题。

接口就像契约。如果你使用的实现方法不在接口中,这意味着你打破了契约,在你的代码和实现之间创建了耦合。

请记住,您的代码应该始终依赖于抽象而不是具体。

通过对象类的强制转换,你基本上是给派生类每个可用的权限,这是一个函数永远不会拒绝即将到来的参数,因为你已经提供了对象将被访问,所以它是危险的,正如@Henrique所说的,如果你需要确保一个对象是一个特定的实现,当你期待一个接口时,那么你的设计肯定有问题。

最新更新