網頁版幾何畫板開發筆記(三)

關於刪除對象 (delete_objs) 和對象之間的內部結構有關, 所以先筆記對象之間的結構. 數據結構

  幾何對象的起點是點(Point)對象. 經過鏈接兩個點構成線(Line), 以一個點爲圓心, 圓上另外一
點能夠作圓(Circle), 線段(Segment)能夠取中點(Midpoint), 兩線或圓(Path)能夠取交點
(Intersection) 等等. 詳細的在研究各對象時候再仔細分析. 那麼對象和對象之間有什麼關係
呢? app

對象之間關係在程序中總結和使用的有三種:
1. 一個對象能夠有 0-* 個子對象. 這裏 * 表示多個的意思.
2. 一個對象能夠有 0-* 個父對象.
3. 一個對象能夠有 0-* 個移動相關的控制對象. 函數

關於第3種關係對象, 在研究Move 的時候用到, 如今暫時略. 以下分析父子對象關係與實現. this

一個對象能夠有多個子對象, 舉例子以下: 
  兩個點A, B可鏈接構成一條線l, 則 l 是A的子對象(l 也是B的子對象);
  還能夠以A 爲圓心, B 爲圓上一點作圓c, 則 c 是A,B 的子對象. 設計

這個例子中, A有 l,c 兩個子對象; B 也有 l,c 兩個子對象; l 有 A,B 兩個父對象; c 也有 A,B
兩個父對象. 對象

一個對象的父對象的數量理論上沒有限制, 例如一個多邊形, 每一個頂點都是多邊形的父對象,
而多邊形的邊數能夠不少不少. rem

一個對象的子對象的數量理論上也沒有限制, 例如一個點, 能夠過該點作無數條直線, 而這些
直線都是這個點的子對象. get

存在的約束關係是, 若是 x 是 y 的父對象, 則 y 是 x 的子對象.
TODO: 當前創建這種父子對象關係的代碼彷佛不太嚴謹, 兩種關係不太對稱, 忘記了當時爲何
兩種關係沒有同步創建的緣由了. 建議好好思考一下, 如何同步創建和維護這兩種關係.
TODO: 因爲這兩種關係存在約束關係, 能夠考慮實現 self_check() 方法約束的驗證. 同步

根據以上分析, 在幾何對象基類 ObjBase 中實現父對象關係的數據結構和相關函數以下:
數據: protected Object[] _parent_objs -- 用於存放此對象的全部父對象. 其可能爲 null 或 [].
使用 _ 作名字開頭, 意思是通常不直接使用/訪問該數據. 子類對象在構造的時候, 一般
設置本身的父對象數據 _parent_objs. io

public Object[] get_parent_objs() -- 獲得此對象的父對象集合, ObjBase 基類的缺省實現是返回
this._parent_objs, (這樣設計是使得)子類能夠重載此實現.

舉例以下, 經過兩個點構造一個新的線段(Segment)時設置父對象:
public static Line Line.new_seg(Point p1, Point p2) {
  this._parent_objs = [p1,p2]; // 設置點p1,p2 爲此線段對象的父對象. 
  ...... 其它代碼略.
}

注意: 此時只是子對象知道父對象(_parent_objs), 也即創建了單向的關係. 此時不知足
約束關係. 當前程序的實現是在 append_obj() 時才創建另外一方向父->子的關係, 因此
問題是, 兩種關係未同時創建, 並且若是子對象未加入到鏈表或不須要加入到鏈表, 則這種
關係也就未完整創建. 思考: 那怎麼作比較好呢?

父關係的使用(已知的可能地方):
1. 一個對象的移動控制對象集合(move ctrl), 缺省是這個對象的父對象集合.
2. 子對象關係是經過父對象關係反向創建的(當前在 append_obj() 中實現)
3. 對象屬性對話框中, 會顯示出此對象的父對象和子對象.
4. (幾何畫板中)Alt+↑選中當前對象的父對象, Alt+↓選中當前對象的子對象.
  咱們不必定實現此功能, 但可適當瞭解此功能.

====

下面繼續筆記子對象. 子對象關係的創建當前在 append_obj() 函數中實現.

public void GeoPad.append_obj(ObjBase obj) {
  for (var i = 0; i < par_objs.length; ++i)
    par_objs[i].add_child(obj);  // 告知每一個父對象, 它增長了一個子對象.
  ... 其它代碼略 ...
}

子對象關係的消除當前在 delete_obj() 函數中實現:
public void GeoPad.delete_obj(obj) {
  for (var i = 0; i < par_objs.length; ++i)
    par_objs[i].remove_child(obj); // 通知每一個父對象, 這個子對象被刪除了.
}

從更精細的代碼任務分解角度來講, append_obj(), delete_obj() 都執行了多種任務, 從而
把事情弄混亂了, 若是分解爲幾個小任務, 如 link/unlink chain, add/remove child, 等等
可能更清晰一些?

子對象關係的使用:
1. 在移動操做以後, 要更新全部被移動對象的子對象(及子子對象)的幾何數據.
2. 刪除對象: 同時刪除全部子及子子對象.
3. 在某些查詢中, 經過限定查詢某個對象的子對象, 能夠大大減小查詢範圍, 從而提升查詢速度.
4. 如父對象關係中, Alt+↓可選擇子對象, 對象屬性對話框中可列出子對象.

移動, 刪除操做對這種關係的具體使用, 之後筆記.

子對象的數據結構和相關函數:
private? Object[] ObjBase._child_objs -- 表示此對象的全部子對象. 缺省爲 undefined.

public Object[] ObjBase.get_child_objs() -- 返回此對象的全部子對象. 缺省實現爲返回 this._child_objs.
  儘管子對象能夠重載, 不過因爲須要維護 _child_objs 集合, 比較麻煩因此不重載爲好.
void ObjBase.add_child(ObjBase child) -- 添加指定子對象. 若是存在則不重複添加.
void ObjBase.remove_child(ObjBase child) -- 刪除指定子對象. 不存在則返回 -1. (通常忽略)

這裏的 add_child(), remove_child() 函數, 是在 GeoPad.append_obj(), delete_obj() 中調用的.

相關文章
相關標籤/搜索