2009-12-17 100 views
7

我是一個新手的設計模式,這裏是我的問題設計模式問題

如果我們有實現它,這個每個類都有不同的屬性,一些類的抽象類。

現在我有另一個(管理員類),其中包含抽象類的數組,我想把一個搜索方法在其中...我怎麼能做到這一點,而不需要投到具體的類?

我有2個想法:

第一個:添加的接口一個額外的水平,這與接口而不是代碼去(即而非澆注混凝土類我將強制轉換爲一個接口。)實施規則... 但這種方式,當我添加另一個類,我將不得不爲它做一個接口,我也將不得不編輯管理器(客戶端),這似乎不是很好。

二解決方案: 它看起來有點怪,仍然需要改進,但其主要目的是使經理或其他任何客戶端可使用抽象類,不知道是誰擴展它或它的屬性的任何東西。

的solutin是folows: 加入將不得不在此改變一個接口,強制執行它來生成其例如字段的完整詳細描述每一個新的項的汽車對象將具有返回具有如下因素

散列映射

字段:{字段類型,fieldValue方法}

例如

  • 模型:{文本, 「福特」}
  • manifactureDate:{日期,「89年12月1日」}

並且每個對象將有也執行該採取 哈希表這樣的方法叫compareFields和比較,它的領域,返回true或錯誤。

現在這樣,我已經解決了許多問題 - 對於貴我將只需要做出一個渲染引擎此HashMap可以顯示 任何項目,而不必知道它的類型。 (再次GUI是另一個客戶端爲抽象類)

- 對於搜索我可以得到包含用戶在抽象項搜索表單和循環進入 領域的哈希表,並調用fieldmethod比較

我還是不怎樣,我會處理複雜的對象(即有另一個對象及其屬性)

我不知道什麼樣的格局是這樣的..這只是一個想法,我想過。

編輯:具體示例

,如果我有一個抽象類項與汽車和公共汽車和水上交通實現它,,每本類都有不同的屬性.... 怎麼可以不強制轉換爲汽車或巴士... 真的很抱歉的長期問題,例如流量管理器搜索使用抽象類某一個項目經理

+0

咦?我很困惑。你在用什麼語言? – 2009-12-17 17:48:28

+1

無論他使用什麼語言。設計模式不關心它們可以在大多數任何語言中實現。 – JonH 2009-12-17 17:50:18

+0

我同意jonH ,,,但任何我可能使用java的方式 – 2009-12-17 17:51:26

回答

9

封裝

封裝狀態的OO原則表示反對不應該的狀態暴露於外部。如果你的對象使用內部信息打破封裝。根據面向對象的設計,仍然可以將搜索標準傳遞給對象,並讓它決定它們是否匹配。

interface IVehicle{ 
    bool doesMatch(Map<String,String> searchCriterion) 
} 

您可以在所有車輛上都有一個interator,並檢索與打破封裝匹配的匹配。車輛的特定實施仍然可以根據需要重新實施。

遊客

否則,我建議你看看Visitor模式。然後這個想法是遍歷所有的對象,並有一個額外的類來處理每種特定類型的處理。這也打破了純粹的封裝(因爲對象需要將其數據公開給訪問者),但它非常優雅。

class VehicleSearchVisitor 
{ 
    Map<String,String> searchCriterion; 
    void visit(Car car) {...} 
    void visit(Bike bike) { ... } 
    .... 
} 

元編程

這是自描述的是另一種概念,這就是所謂的元編程對象的想法。然後表示層反思其他對象知道如何處理它們。傳統上這被認爲是一種先進的面向對象技術。您可以創建自定義註釋來描述類的字段,以便表示層可以動態地呈現適當的標籤。例如,與hibernate註釋一起使用相同的想法。元編程需要小心完成,否則你會遇到其他問題。

Insteanceof

使用insteanceof也是內省的形式(因爲你問的對象爲它的類),通常氣餒。不是因爲它本身是錯的,而是因爲它傾向於被濫用。只要有可能,就依靠傳統的面向對象原則。濫用instanceofcode smell。總而言之,我會建議使用訪問者進行搜索,並且不要使用元編程用於表示層,而是爲每種類型的車輛創建一個簡單頁面。

+1

我打算推薦第一個答案 - 這對我來說最有意義。這樣,每個IVehicle決定它是否符合搜索條件。 – 2009-12-17 20:17:41

4

你似乎在描述什麼史蒂夫·耶格調用Universal design pattern.

使用鍵值對與GUI可以在簡單的情況下工作,但很難讓它看起來不錯。除非你的對象層次結構很深並且必須具有很強的可擴展性,否則你可能需要爲每個具體類創建一個單獨的表單,因爲這樣做工作量較少,並且看起來會更好。您仍然可以重用共享GUI組件,因此添加新的具體類應該非常簡單。

6

好吧,所以你擴展類,而不是實現一個接口。如果你有Bus,Car,Truck,Train類,並且他們都實現了IVehicle,它需要一個返回可排序/可搜索值的函數,那麼你將能夠將它們全部引用爲IVehicle類型,並在所有類中調用該方法。

ActionScript 3代碼:

package com.transportation.methods { 
    public interface IVehicle { 
    function getSpeed():Number; 
    function getOtherSortableOrSearchableValue():*; 
    } 
} 

public class Car extends Sprite implements IVehicle 

您需要在汽車類中定義getSpeed()和getOtherSortableValue(),並可以將其稱爲無論是汽車還是動力車。由於我的例子中的所有交通模式都會實現IVehicle,只要你將它們稱爲IVehicles,你可以稱之爲這兩個功能。

+0

這是我的第二個方法(哈希映射方法)不是嗎? – 2009-12-17 18:26:57

+0

非常好,是的。 – Aaron 2009-12-17 18:46:03

+0

這實際上忽略了原來規定的限制之一,即每輛車可能具有不同的屬性。所以一輛汽車可能有一個getSpeed(),但也許是一個POGO棒不會。一個彈簧杆可能有一個getBounceHeight(),但這對汽車沒有意義。散列圖想法可以處理這些情況,但這個特定的答案不會。 – 2009-12-17 20:20:41

0

我沒有看到你使用的是什麼語言,但爲什麼沒有抽象類實現接口?這樣,只要它們都從實現該接口的抽象類繼承,那麼具有多少個具體類就沒有關係。

這裏的,如果你使用的是Java層次結構是什麼樣子:

public interface IVehicle {/*your code goes here*/} 

public abstract class AbstractVehicle implements IVehicle{/*your code goes here*/} 

public class Car extends AbstractVehicle{/*your code goes here*/} 

這些都會,當然,可以在不同的文件中定義。

+0

如果我爲船增加了一個新班級,並且它的屬性與汽車不兼容,並且不能添加到車輛界面中,那麼我該怎麼做? – 2009-12-17 18:22:36

+0

@Ahmed Kotb - 這樣做的一種方法是向接口添加getAttributes()方法,該方法返回包含屬性的鍵/值對的HashMap。如果需要,調用類可以查詢HashMap的哪些屬性(鍵)存在。可以在抽象類中定義search()方法,以便在實際搜索發生之前執行此檢查。 – ssakl 2009-12-17 18:35:26

+0

是的,我想在第二個建議中做什麼,但我想知道是否有更好的或者如果這已經是我可以閱讀的設計模式 – 2009-12-17 18:38:35

0

如何能夠在不強制轉換爲汽車或巴士,例如流量管理器搜索使用抽象類某一個項目經理

我做這件事的方法是抽象類有一個抽象方法,它返回一個ID值(比如一個枚舉值),該值指示該對象是哪個具體類型,並讓每個具體類都重寫以返回其ID值。

或者我會嘗試使用C++的RTTI工具或Python的instanceof()函數。

這有幫助,還是我回答錯誤的問題?

+0

所有這些都不是非常OO-ISH解決方案,它們會破壞LSP。 – 2009-12-17 18:21:09

+1

是的,我會做到這一點,當我沒有其他選擇,因爲使用實例 - 意味着經理類必須知道具體的類,我認爲不是最好的事情在OOP作爲馬丁尼說 – 2009-12-17 18:25:47

2

在我看來,這似乎是某種「集中式」存儲庫模式。我不認爲這是個好主意。

你推薦什麼你是不是具有廣義搜索的一種集中的方式,你應該有幾個專門倉庫:一個是汽車,一個是船,一個平面等

各存儲庫瞭解各個對象的細節。然後,您可以將這些專用存儲庫之間的常見操作分解到存儲庫基類或接口。當你不關心細節的時候,你使用基本的Repository接口。當你關心你使用專門版本庫的細節時。

以下是一個Java一個簡單的例子(我要走了getter/setter方法出來急促 - 讓你的領域進行的公共):

interface Vehicle { int id; int maxSpeed; } 
class Car implements Vehicle { int doors; int id; int maxSpeed; } 
class Boat implements Vehicle { int buoyancy; int id; int maxSpeed; } 
class Plane implements Vehicle { int wingSpan; int id; int maxSpeed; } 

interface VehicleRepository<T extends Vehicle> { 
    T getFastest(); 
    T getSlowest(); 
    T getById(int id); 
} 

interface CarRepository inherits VehicleRepository<Car> { 
    List<Car> getCarsWithTwoDoors(); 
} 

interface BoatRepository inherits VehicleRepository<Boat> { 
    Boat getMostBuoyantBoat(); 
} 

interface PlaneRepository inherits VehicleRepository<Plane> { 
    List<Plane> getPlanesByWingspan(); 
} 
+0

是的,這是我的第一個建議...通過創建一個額外的接口級別,我認爲這裏唯一的問題是,當我添加像火箭這樣的項目時,我將不得不創建一個火箭儲存庫? – 2009-12-17 18:36:12

+0

是的。我不認爲這有什麼問題,因爲你不必改變現有的類來增加火箭。如果你使用集中式的東西,你必須在每次添加其他東西時改變它。 – 2009-12-17 18:40:01

2

這聽起來像是訪問者模式的工作。你有一個抽象對象的集合,你不知道每個對象是什麼。使用Visitor可以迭代所有對象並執行特定於每個對象的操作。 GOF Patterns書提供了有關訪問者模式的詳細信息,但我會盡力在此提供一個良好的Java示例。

public class Vehicle { 
    public void accept(VehicleVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public interface VehicleVisitor { 
    public void visit(Vehicle vehicle); 
    public void visit(Car car); 
    public void visit(Bus bus); 
    public void visit(Truck truck); 
    // Augment this interface each time you add a new subclass. 
} 

public class Car extends Vehicle { 
    public void accept(VehicleVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public class Bus extends Vehicle { 
    public void accept(VehicleVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public class Truck extends Vehicle { 
    public void accept(VehicleVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public class VehicleSearch implements VehicleVisitor { 
    protected String name; 
    public List<Vehicle> foundList = 
     new ArrayList<Vehicle>(); 
    public VehicleSearch(String name) { 
     this.name = name; 
    } 
    public void visit(Vehicle vehicle) { 
     return; 
    } 
    public void visit(Car car) { 
     if (car.getModel().contains(name)) { 
      foundList.add(car); 
     } 
    } 
    public void visit(Bus bus) { 
     if (bus.getManufacturerModel().contains(name)) { 
      foundList.add(bus); 
     } 
    } 
    public void visit(Truck truck) { 
     if (truck.getLineModel().contains(name)) { 
      foundList.add(truck); 
     } 
    } 
} 

public class Manager { 
    protected List<Vehicle> vehicleList; 
    public List<Vehicle> search(String name) { 
     VehicleSearch visitor = 
      new VehicleSearch(name); 
     for (Vehicle vehicle : vehicleList) { 
      vehicle.accept(visitor); 
     } 
     return visitor.foundList; 
    } 
} 

乍一看,是的,你可以簡單地添加一個搜索方法對車輛類並調用該列表中的每個成員,但訪問者模式允許您通過汽車這樣的列表定義多個操作您無需爲每個車輛類添加新方法。

雖然Visitor模式的一個缺點是訪問者本身需要在添加一個新的訪問對象類時進行更改。在本例中,如果您將RocketShip車輛添加到系統中,則需要爲訪問者添加visit(RocketShip rocketShip)方法。

您可以通過創建VehicleVisitorTemplate來覆蓋所有訪問方法來緩解此問題。您的操作對模板類進行子類化,然後只需要重寫所需的方法。當你需要添加一個新的類和訪問方法時,將它添加到接口和模板類中,然後除非必要,否則不需要更新所有其他操作。