全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2558
推到 Plurk!
推到 Facebook!

拋磚引玉篇:資料結構導向還是物件導向合適?

 
neoart
版主


發表:22
回覆:582
積分:425
註冊:2003-05-09

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-05-19 08:07:46 IP:61.56.xxx.xxx 未訂閱
專案,不管是不是網頁型態還是swing client的型態的專案. 我想萬變不離其宗的是:都是在對資料庫的操作.  但就分析的角度之不同,對於資料物件的定義也就有具體與抽象之分. OK.舉例而言,一個人事的最小單位的資料:"工作人員"而言. 可以先制定一個"人"這樣的一個基礎類別.再具體的去擴充: ex:
class man{//先別考慮性別歧視,好嗎?
  String name;
  String id;
  public String getName(){return name;}
  public void setName(String _name){name=_name;} 
   
}
class staff extends man{
   int salary;int rank.....
    ....同樣的也是一些getter and setter,用以存取屬性
}    有了這樣一個具體的類別之後.接著就是處理他的人事機構(機關)類別:
  class HR_unit{
    public man onBoard(man you){
       //報到,把"人型"資料inser到db,並賦予員工代號
     }
    public void resign(man man2leave){
       //離職,把"人型"資料由db中 delete,收回代號
     }
    ......其他有的沒的......
  }
這樣的實作方式,對SA而言是很具體.製作UML及programmer擬定元件類別的架構有不錯的幫助. 怕coddig這些getter & setter嗎?放心,有很多人跟你一樣.所以早就有database-->table-->list fields--->generate getter & setter這樣的一些工具了(叫DAO(data access object)plug-in,用以產生某table欄位相對應的DataAccessObject 類別. 以上是一種以SA的角度去設計的方式,很直覺,不是嗎? 另一種方法,已經有不少公司(至少我朋友們也聽過這樣的一些idea),是以資料導向的設計方式. 也就是說以database的sql組裝的思維出發的一種設計模式.舉個例子,就應該可以會心了
  Class DataRow{
    //...存放著欄位,順序及其資料
    public Object get(int fieldIndex){
             //findout field name....
            return    storedHashMap.get(findFileNameIndex);
    }
    public void set(int fieldIndex,Object obj){
      //find out field index..... 
      storedHashMap.set(fieldIndex2Name,obj);
    }
  }
  Class DataBaseTable{
     String tableName,String pk_column_name;
     public DataRow findRow(pk value){
                      sql="select * from .... where ....";
                      List list=getBySQL(sql);
                      return (DataRow)list.get(0);//如果有的話
                     }
     public DataRow insertRow(DataRow data2inc){
                     sql="insert into.....";
                     data2inc.set(pkfield,newid); //pk指定
                     return data2inc;
                    }
     public List    getBySQL(string sql){
                         ....
                         ResultSet rs=..... 
                         return(resultsetToDataRow(rs);
                     
                    }
     public void    doUpdate(DataRow data2update){sql="update.....";}
     public void    doDelete(DataRow data2del){sql="delete ....";}
     private List resultsetToDataRow(ResultSet rs){
          //這裡才是DataRows的搖籃,
          //負責產生,指定DataRow中的欄位及值的對映資料
     }
  }
這是很類似ADO的get(欄名或欄位順序索引),set(欄名或欄位順序索引,值)的資料列物件 而在資料庫中的每一個table,都是上例中的DataBaseTable類別中的一個實體(instance)罷了 (用過MS ADO或是直接操作jdbc resultset的人都應該有概念) 這對programmer而言,是非常一勞永逸的設計,不過,相對的.對OO-SA而言,就有著不少的認知上的差距 因為當一切都又回歸到資料庫的思考時,會與上一個以類別為出發點的設計模式格格不入. 兩者沒有所謂的對與錯.只有適不適用(事實上,所有的design patter都是如此,就是在時機問題罷了) 前者(OOSA DataAccessObject)對於公司套件的模組化(塑組工程)有相當的必要性,然,對於不必要的資料進出控制,非常麻煩.況每有架構異動時,修改工程也相對不少. 後者(Data aspect designe)對於日後gui與data的建立有著息息相關的相依性,然,不利於格局開擴(因為所想所見都是資料),有其發展界限 小弟個人是比較 "習慣" Data aspect designe的方式.日後會再就此點延申與各位討論(如果天氣一直都是這樣熱到我睡不著的話).不知其他SA/SD/programming 前輩可否提供一下寶貴意見?以供小弟修正,以免誤人誤己.謝謝. (以上程式片段,均為虛構,如有雷同,純屬巧合) ====================================================================================== 參考: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObjectAssembler.html 發表人 - neoart 於 2004/05/19 09:17:16 發表人 - neoart 於 2004/05/19 09:29:29
neoart
版主


發表:22
回覆:582
積分:425
註冊:2003-05-09

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-05-23 19:16:41 IP:61.56.xxx.xxx 未訂閱
有了上述的DataRow及DatbaseTable這兩大類別之後,看其來好像沒什麼用? 嗯.修行在個人了.就看你怎麼用了. 想想.如果我們可以支援序列化的功能,方便日後直接以I/O stream來傳遞資料的話.那,這樣是不是更符合網路化的發展呢? (之前我也有討論為什麼不直接用jdbc的resultset的問題.原因無他,問一下貴公司的網管,敢不敢把database的port開放給外存取?),況且,有了序列化的功能之外,可以支援檔案存放,也可以支援暫時性(client jvm下)的複製及操作---也就是無中生有.這是不是更有想像空間?... 要這樣作.是不是要把我們的DataRow類別做很大的修改?  呵呵,別忘了,我們是用java的啊.只要你的資料類別內所參考的資料都支援序列化的話,都宣告成可序列化的類別.只要一句話:
  Class DataRow implements java.io.Serializable <-----可序列化
    ...
    ...其他照舊....
屆時,DatabaseTable類別所產生的DataRow及其List,就可以支援序列化的方式傳遞了: client <-----I/O Stream--->service Listener(such as Servlet,RMI,EJB...) 再把你的DatabaseTable物件包在Service Listener中即可,這樣一來,安全性及擴充性就可以兼顧了. 或許你會問,那之前以塑模導向設計中的各個角色,在這個架構中會是什麼,嗯.這個問題,見人見智了,你可以放在service listener中,client裡. 都是以邏輯物件的方式存在.當然....上一篇所言的兩個設計方式是不抵觸的,也就是....角色物件都是由資料所構成的話.自然應該有一個支援export To Data的方式,也應該會有一個以DataRow或相關方式的建構元(Constructer) 當然,也有直接設定這些角色類別都是支援序列化的方式以供日後發展.這,更需要一點想像力才行了. 以繪圖軟體說明好了. 繪圖軟體中,一定會提供"線","圓","方"等類別(都是直接繼承自javax.swing.JLabel),在畫布中的任一物件,都是上述這些類別的實體,只是有不同的內容(ex color,position,size....),造就出多姿多彩的世界.說到了繪圖,就不免要用mouse去拖拉或決定大小位置.這還算事小(反正在每個類別去做右鍵menu的功能及其相對設定,個別擊破了). 辛辛苦苦地畫完了圖,總該可以存檔吧.嘿嘿,問題來了,mouselistening是不支援序列化的.那之前我們所聊的不就是破功了? 山不轉路轉囉:如我所說的,每一個類別都支援export to data輸出到資料流存檔,反之,也要有其建構元的方式,以便檔案I/O,日後再由繪圖軟體去建構並填入相關的內容就可以了. 這點.我個人認為XML應該可以應付這樣的需求,anyway,扯太遠了.下次我們再聊一下有了DataRow這樣的東西.swing gui可以如何應用. 參考: http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectInputStream.html http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectOutputStream.html 發表人 - neoart 於 2004/05/23 19:48:46
pipp
一般會員


發表:2
回覆:21
積分:9
註冊:2003-10-22

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-05-25 10:06:43 IP:61.220.xxx.xxx 未訂閱
我不是前輩,發表的意見可能也不具價值    目前不管是JDO or Hibernate 都希望能把系統和DB的關係給切開, 系統能夠不限定在哪種DB,甚至有的可以不用寫sql語法, 試圖讓程式設計師能夠更專心的系統的應用(理想拉) 而且如果已經有人寫好的架構元件,是不是會更方便, 更容易找到資料?(偷懶至上) 但還是要經過study 拉~~ 愚見
neoart
版主


發表:22
回覆:582
積分:425
註冊:2003-05-09

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-05-25 12:32:30 IP:61.64.xxx.xxx 未訂閱
引言: 我不是前輩,發表的意見可能也不具價值 目前不管是JDO or Hibernate 都希望能把系統和DB的關係給切開, 系統能夠不限定在哪種DB,甚至有的可以不用寫sql語法, 試圖讓程式設計師能夠更專心的系統的應用(理想拉) 而且如果已經有人寫好的架構元件,是不是會更方便, 更容易找到資料?(偷懶至上) 但還是要經過study 拉~~ 愚見 < face="Verdana, Arial, Helvetica"> 當然這要看你的底層設計的是否周詳了,我的用意是對一般的新增刪除修改預先組裝出sql ex: String beginSQL="update 你的table名稱"; 再由DataRow去列舉出所有異動到的欄位及值,由DataTable去組出 key=value,...的語法. 通常第一次寫好,之後就不用寫了,如果是有一對多的話,那就考慮去overwrite(overload with multi-related Data List)這一段,同樣的,delete也是一樣,找出該筆DataRow的pk值,由DataBaseTable類別自動組出sql,執行之(也就是由DataRow的傳入來"觸發"Factory的執行) 一般這類的Factory類別(專門在製造或初處理的單元),都會有些不同的finder以供資料索引之需要 ex: DataRow find(int pkValue)......或 DataRow find(String pkValue).... 這就是底層的實務工作,在這類別中,你可以套用ConnectionPool達到比較好的效能. 再進一步而言,連查詢的條件都可以以類別的方式來定義,以供日後的再利用(ex:報表工具定義出這樣的東西) 如果有空的話,麻煩pipp可以介紹一下Hibernate的架構及概念好嗎?
neoart
版主


發表:22
回覆:582
積分:425
註冊:2003-05-09

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-05-31 10:11:01 IP:61.64.xxx.xxx 未訂閱
有了資料來源,就可以加入gui,使之可以呈現. 一般最常見的,就是JCombobox & JTextField/JTextArea(反正就是javax.swing.text.JTextComponent子類別就是了). JCombobox就要有點sense了.事實上swing都是有很強烈的MVC精神(Model & visual & control). 為了日後可以大量處理,建議設計一個基礎類別.例:
 Abstract class DataBindGuiObj extends javax.swing.JComponent{
   //宣告成JCombonent,以供日後可以直接在Jbuilder中引用.
   
   public void JComponent getJComponent(){//傳回綁著的JComponet}
   public Object getValue();//虛之,子類別複蓋.容後
 }
  class DataBindJtxt extends DataBindGuiObj{
           JTextComponent _myTextCmp;
           String _text;     
           DataBindJtxt(JTextComponent jtxt,String initStr){
               _myTextCmp=jtxt;
               _myTextCmp.setText(initStr);
               _text=initStr;
           }
    public Object getValue(){return _myTextCmp.getText();}
  }
  //JCombobox之於databinding就一言難盡了.參考:
  http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/ComboBoxModel.html
  http://java.sun.com/docs/books/tutorial/uiswing/components/combobox.html
  JCombobox要考慮editable與否,這一點請在實作時加入這一項考量
  ---------------俟你實作完這些類別之後,就可以設計他的容器-------------
  Abstract Class DataPanel extends JPanel{
     protected _initDataRow;
     public void doGenerateDataBind(DataRow datarow);//子類別實作,因為我們不知道未來你有多少欄位及多少gui要去mapping
     public DataRow doGenerateData(){
        //列舉本容器在所有的doGenerateDataBind()中,所產生的DataBindGuiObj
        //用DataBindGuiObj.getValue(),設定到_initDataRow的相對欄位,
         return _initDataRow;//傳回去user 設定的資料
     }
  }
  DataPanelPersonalData extends DataPanel{
     //....用JBuilder類的IDE去拖拉設定gui物件的位置
     //.....
     public void doGenerateDataBind(DataRow datarow){
       _initDataRow=datarow;
       DataBindJtxt(jtxtStaffName,dataRow.get("staff_name").toString());
       ...其他以類推...      
     }
  }
有了這樣的元件及容器,就可以大量設計自已專案的編輯設計畫面. JTable就要就TableModel來設計與資料的對應. 參考:http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JTable.html Tips: 新增及修改都是一樣的東西,為什麼?因為資料都是一樣的.只是一個是空白資料,一個是有內容的資料. 光是有data與gui的對應,這還不夠,對於JTextComponent而言,一定要有檢核機制,下次再討論了. ====================以上片段,皆為虛構,如有雷同,純虛巧合================================ 發表人 - neoart 於 2004/05/31 10:16:10
ddt0927
一般會員


發表:0
回覆:1
積分:0
註冊:2004-06-02

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-06-03 15:31:52 IP:140.113.xxx.xxx 未訂閱
Neoart兄,您好!    我很遜的...只是因為論文上的需要...逼不得已才去看EJB    事實上...連基本的J2SE我都還不太懂>.<    所以很多名詞我可能會誤解你的意思...請多包含    那我就來說說我的愚見了    你所說的Data aspect design觀念似乎跟entity bean的運作方式如出一轍    就連程式的長相都差不多 說不定其前身就是從這來的也說不定 包括序列化,加上管理網路化多人存取資料庫, 在資料一致性上的問題之回復機制在
neoart
版主


發表:22
回覆:582
積分:425
註冊:2003-05-09

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-06-03 16:25:06 IP:61.64.xxx.xxx 未訂閱
引言: Neoart兄,您好! 我很遜的...只是因為論文上的需要...逼不得已才去看EJB 事實上...連基本的J2SE我都還不太懂>.< 所以很多名詞我可能會誤解你的意思...請多包含 那我就來說說我的愚見了 你所說的Data aspect design觀念似乎跟entity bean的運作方式如出一轍 就連程式的長相都差不多 說不定其前身就是從這來的也說不定 包括序列化,加上管理網路化多人存取資料庫, 在資料一致性上的問題之回復機制在>< face="Verdana, Arial, Helvetica"> 非常謝謝你的參與,基本上在下必須說明的是這東西跟ejb沒有太大的關係,原來的用途是敝人在做非同步交易時的一些idea所造出來的東西(也就是無心插柳之做罷了). 另一方面.對於data feild而言,entity bean在實作(CMP)會產生對每個欄位產生他的getter & setter(ex:getName(...),setName(...))每一個table及其產生的record都是一個entity bean類別,不過為了日後快速作業(ex:兩筆資料間相互比較等這類的功能,甚至是允許user runtime時自增欄位存放暫時性資料),我是回頭以ado的get & set 的思維設計的(也就是支持欄位索引的方式是by column name or by column index),以便日後gui元件/容器與資料列之間的對映,乃至於抽象化的設計,這樣想來.回歸到以資料列比較好想. 最後,entity bean的運用,都嘛是要有session bean在配合吧?(sorry,我只有用過session bean),如何在資料有必要cache在client中可以運用?這就是很麻煩的事了.另外,在jtable這類的介面中,要有分頁才行,我們的資料動輒上萬筆,不分頁,當然不行了. 對於EJB而言,在下真的幫不上忙,畢竟ejb在本單元的應用中,是提供遠端介面的方法的管道罷了.別忘了,我在開始就開門見山地以DataBaseTable類別做為factory類別,跟有沒有ejb是沒有關係的. 有錢有有錢的玩法,沒錢也可以用rmi來做也可以.這就是專案磨練出來的實作原則. 這東西,要用design pattern之"service locator & factory " pattern來想了.也就是...資料進出方法都是介面,至於實作是由ejb remote interface還是rmi還是http url connection input/outputstream ? 對你的caller而言是無關的. 不過有ejb真的是很好用的,事實上.我們也真的是因為session bean之故,可以少做transaction & resource(bean pool)的控制,這一點.也是非常銘感五內的. 小弟是打算本單元是專注在db之於swing上的binding,再牽拖到一些可能用到的pattern,會是希望你有空來補充一下.感恩啦.
neoart
版主


發表:22
回覆:582
積分:425
註冊:2003-05-09

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-08-10 10:30:43 IP:61.64.xxx.xxx 未訂閱
有了swing/gui,顯示資料要注意到什麼? 沒錯,是格式的問題. 或許你會問:"為什麼要有格式?我明明可以在sql中,指定資料的格式就好了咩" 是沒錯,不過這就失去元件化的獨特性質了--減少相關性 今天你的database是oracle,明天呢?你的code是不是要大幅改寫了? MVC的精神就是切分的很清楚:資料歸資料,顯示歸顯示.控制又歸控制,為的是可以應付日益複雜的現實世界(OK.我承認是不可能的,不過,儘量吧). 如何解決? 別忘了.我們是用java的.有前人的血汗,我們可要善用才行,才不會辜負前人的心血. 那就用formater: ava.text.Format系列,有Decimal format 還有DateFormat.這些工具可以方便你做形式轉換,不用再去傷腦筋去補幾位零或是哪一位是什麼字元. 參考: http://java.sun.com/j2se/1.4.2/docs/api/java/text/DecimalFormat.html http://java.sun.com/j2se/1.4.2/docs/api/java/text/DateFormat.html 這東西是非常好用的.套用我們之前的DataRow物件吧,如:
==============================================
import java.util.Date;
import java.sql.TimeStamp;
import java.text.SimpleDateFormat;
......
.......
  TimeStamp dateOfReg=(TimeStamp)dataRow.get("dateOfReg");
  //大部分日期物件從database取出時是java.sql.TimeStamp型態.你要查一下
   Date dt=new Date(dateOfReg.getTime());
  SimpleDateFormat sf=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
  String regDateData=sf.format(dt);
  //反之,轉成日期物件是formater.parse
   Date newDate=sf.parse("2004/05/03  23:32:15");
  ....再塞入 resulset去set to database..........
===============================================
眼尖的user一定會想到順便做驗證的工作(ex:2001/2/31),這些formater也幫你做到了.
  try{
    .... 
     SimpleDateFormat sf=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    ....
     sf.setLenient(false);//這很重要,不然20040231會轉成20040302
     Date dt=sf.parse("2004/02/31");
     ...
    ....
  }catch(java.text.ParseException pe){
     //嗶一下,格式錯誤...
  }
==================================== 再精實一點,建議你用key event去罩除某些不必要的輸出入,這會更直接. 接著,再把這些東西綁到我們之前寫的"DataBindGuiObj"類別,就可以做到我們之前強調的DB無關原則了. 這些東西,小弟都想的到,JCP沒想到嗎?放心,他們也有類似的規格: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/InputVerifier.html 開發者要覆蓋他的shouldeYeieldFocus 及 verify函數才行. 因為實作碼有點長,有興趣的user請參考Maning的書(天瓏有中文版) http://www.manning.com/sbe/ -------------------------專案未完人------------------
neoart
版主


發表:22
回覆:582
積分:425
註冊:2003-05-09

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-08-11 14:25:30 IP:61.64.xxx.xxx 未訂閱
designe pattern之於swing client專案的運用,可以是非常的豐富. 像是command pattern或是memeto pattern,還有compose pattern 坊間上也有不少書在討論這東西.可以視需要斟酌使用. 既然本單元叫做拋磚引玉,小弟也拋磚引玉一下:command pattern的運用. command pattern的運用,之於editor而言,非常重要,特別是功能鍵林立的GUI而言. 更是重要. command pattern的用意是把執行的內容包裝在某一類別中,大家最熟悉的,莫過於以下的宣告了
================================
interface CommandRun {
  public void execute();
}
....
....
...
 File fileToEdit;
 ....
....
Class Openfile implements CommandRun{
   public void execute(){
    fileToEdit=.....//開檔
   }
}
Class Closefile implements CommandRun{
   public void execute(){
      file.close();//存檔
   }
}    Class SetText implements CommandRun{
  int x,int y,String text;
   SetText(int _x,int _y,String _text){
    x=_x,y=_y,_text=text;
    .....
   }
  public void execute(){ 
     edtor.setText(x,y,text);
      .....
   }
}
=============================
透過command pattern,可以把指令存成放在不同的地方,不只是某個按鍵,也可以存錄在某個指令queue中,聰明的你一定想到是什麼了,沒錯,是很類似精靈(wizard)那類的輔助物件之中. 而且還可以套用到"回上一頁...."等往復功能的需求. Pattern個別使用,是會看不出他的威力的,最常與command pattern運用的pattern可能是memento pattern或是 chain of responsibility pattern memento pattern是藉由存放資料的狀態,以便日後回復(如undo的功能,或是file restore的過程),當然,為了安全起見,這些執行的過程,都是有權限設定的.只有執行單位(同一套件吧?)才可以使用這些函數. 而chain of responsibility也是有一個類似一個responsible介面來做的. ex:
===============================================
Interface Responsible{
   public   Responsible getNextHandler();
   public  void doResponse();
}
===============================================
若要以文字說明的話,我想直接以例子來說責任鏈會比較好懂:像是一些"Help"介面(windows做的不錯),都是有下一步,下一步...的選擇,而在每一個詢問中,都會有些user要填寫的事項,當然也因為填寫的條件不同,"下一步"會出現的介面也就不同了.直到沒有下一步的時候,系統就要做出回應. 而在現實生活中,以點菜的過程可以說是最鮮明的例子了.大家可以想像一下waiter就是系統中的Help介面.而每一頁菜單或是waiter在點菜過程的詢問(單點啦,西點還是中式啦....),就是Help的responsible的呈現了. 所以,要做個精靈這一類的東西,不是什麼難事哦,試一下吧. -------------------專案未完人--------------------------- 發表人 - neoart 於 2004/08/11 18:21:22
系統時間:2024-04-27 17:15:33
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!