熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

澄清Java語言接口與繼承的本質

2013-11-15 11:37:45  來源: JSP教程 

  計算機學院研二的兄弟與我討論Java一見面幾個問題全是關於接口接口有什麼用?為什麼要用接口?什麼時候該使用接口?很慶幸他們不是問我Java如何連接SQL Server或者是如何開發JEE應用這類問題有殺傷力避之則吉今年計算機學院本科有個畢業設計課題是做JME選這個題目的學生在月末都還在苦著臉研究javautil*這個包這個這個……唉
  
  大多數人認為接口的意義在於頂替多重繼承眾所周知Java沒有c++那樣多重繼承的機制但是卻能夠實作多個接口其實這樣做是很牽強的接口和繼承是完全不同的東西接口沒有能力代替多重繼承也沒有這個義務接口的作用一言以蔽之就是標志類的類別(type of class)把不同類型的類歸於不同的接口可以更好的管理他們OO的精髓我以為是對對象的抽象最能體現這一點的就是接口為什麼我們討論設計模式都只針對具備了抽象能力的語言(比如c++javac#等)就是因為設計模式所研究的實際上就是如何合理的去抽象(cowboy的名言是抽象就是抽去像的部分看似調侃實乃至理)
  
  設計模式中最基礎的是工廠模式(Factory)在我最近的一個很簡單的應用中我想盡量的讓我的程序能夠在多個數據庫間移植當然這涉及很多問題單是如何兼容不同DBMS的SQL就讓人頭痛我們不妨先把問題簡單化只考慮如何連接不同的數據庫
  
  假設我有很多個類分別是MysqljavaSQLServerjavaOraclejavaDBjava他們分別連接不同的數據庫統一返回一個Connection對象並且都有一個close方法用於關閉連接只需要針對你的DBMS選擇不同的類就可以用了但是我的用戶他會使用什麼數據庫?我不知道我希望的是盡量少的修改代碼就能滿足他的需要我可以抽象如下接口
  
  package orgbromontest;
  public interface DB
  {
  javasqlConnection openDB(String urlString userString password);
  void close();
  }
  
  這個接口只定義兩個方法沒有任何有實際意義的代碼具體的代碼由實作這個接口的類來給出比如Mysqljava
  
  Package orgbromontest;
  import javasql*;
  public class Mysql implements DB
  {
  private String url=jdbc:mysql:localhost:/test;
  private String user=root;
  private String password=;
  private Connection conn;
  public Connection openDB(urluserpassword)
  {
  //連接數據庫的代碼
  }
  
  public void close()
  {
  //關閉數據庫
  }
  }
  
  類似的當然還有Oraclejava等等接口DB給這些類歸了個類在應用程序中我們這樣定義對象
  
  orgbromontestDB myDB;
  
  使用myDB來操作數據庫就可以不用管實際上我所使用的是哪個類這就是所謂的原則但是問題在於接口是不能實例化的myDB=new DB()這樣的代碼是絕對錯誤的我們只能myDB=new Mysql()或者myDB=new Oracle()麻煩了我還是需要指定具體實例化的是哪個類用了接口跟沒用一樣所以我們需要一個工廠
  
  package orgbromontest;
  public class DBFactory
  {
  public static DB Connection getConn()
  {
  Return(new Mysql());
  }
  }
  
  所以實例化的代碼變成myDB=DBFactorygetConn()
  
  這就是種模式中最基礎的普通工廠(Factory)工廠類負責具體實例化哪個類而其他的程序邏輯都是針對DB這個接口進行操作這就是針對接口編程責任都被推卸給工廠類了當然你也可以繼續定義工廠接口繼續把責任上拋這就演變成抽象工廠(Abstract Factory)
  
  整個過程中接口不負責任何具體操作其他的程序要連接數據庫的話只需要構造一個DB對象就OK而不管工廠類如何變化這就是接口的意義抽象
  
  繼承的概念不用多說很好理解為什麼要繼承呢?因為你想重用代碼?這絕對不是理由繼承的意義也在於抽象而不是代碼重用如果對象A有一個run()方法對象B也想有這個方法所以有人就Class B extends A這是不經大腦的做法如果在B中實例化一個A調用A的Run()方法是不是可以達到同樣的目的?如下
  
  Class B
  {
  A a=new A();
  arun();
  }
  
  這就是利用類的聚合來重用代碼是委派模式的雛形是GoF一貫倡導的做法
  
  那麼繼承的意義何在?其實這是歷史原因造成的最開始的OO語言只有繼承沒有接口所以只能以繼承來實現抽象請一定注意繼承的本意在於抽象而非代碼重用(雖然繼承也有這個作用)這是很多Java爛書最嚴重的錯誤之一它們所造成的陰影我至今還沒有完全擺脫壞書害人啊尤其是入門類的流毒太大什麼時候應該使用繼承?只在抽象類中使用其他情況下盡量不使用抽象類也是不能實例化的它僅僅提供一個模版而已這就很能說明問題
  
  軟件開發的萬惡之源一是重復代碼而不是重用代碼二是爛用繼承尤以c++程序員為甚Java中取締多重繼承目的就是制止爛用繼承實是非常明智的做法不過很多人都不理解Java能夠更好的體現設計這是讓我入迷的原因之一
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19330.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.