对象投射是一种好习惯吗?

bro*_*and 9 design-patterns casting

面向对象的编程语言,例如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;   
Run Code Online (Sandbox Code Playgroud)

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

public class Base
{
  public void base(){}
}

public class Derived extends Base
{
  public void derived(){}
}

Base b = new Derived();
b.base();
Run Code Online (Sandbox Code Playgroud)

派生类具有基类具有的所有方法,以及更多.没有理由不能通过调用派生类构造函数来创建基类.

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

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

Hen*_*los 8

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

派生类型必须完全可替代其基类型.

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

转换的问题是,如果您需要它将Base类对象转换为Derived类,则意味着您违反了LSP.

如果您需要在期望接口时确保对象来自特定实现,那么您的设计肯定存在问题.

接口就像合同.如果您使用的是不在接口中的实现方法,则意味着您正在破坏该合同,从而在代码和实现之间创建耦合.

请记住,您的代码应始终依赖于抽象而非结果.