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

时间:2015-06-09 07:53:30

标签: 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;   

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

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是一个抽象类)。它看起来更清晰,更简单。另一方面,当你处理interfaces, object typecasting comes in handy时。另一个例子是List<Object>列表,我有时会在某些类中看到它。这意味着您可以在此列表中保存所有可能的类。之后,如果您知道它是什么类型,您可以将其转换为原始版本。如果只保存要列出的特定类,即List<String>List<MyClass>,则不会更清楚。是否正在使用List<Object>良好的设计实践?

2 个答案:

答案 0 :(得分:8)

在设计类层次结构时,您始终必须牢记Liskov's Substitution Principle (aka, LSP)

  

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

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

强制转换的问题在于,如果您需要将Base类对象转换为Derived类,则意味着您违反了LSP。

如果您需要确保某个对象来自特定的实现,那么您的设计肯定存在问题。

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

请记住,您的代码应始终为rely on abstractions rather than concretions

答案 1 :(得分:0)

通过使用Object类进行转换,基本上为派生类提供了每个可用的权限,即函数永远不会拒绝即将发生的参数,因为你已经提供了对象的访问权限,所以它很危险, 并且根据@Henrique的说法,如果你需要确保一个对象是一个特定的实现,当你期望一个接口时,那么你的设计肯定会出现问题。