2009-12-17 57 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来覆盖所有访问方法来缓解此问题。您的操作对模板类进行子类化,然后只需要重写所需的方法。当你需要添加一个新的类和访问方法时,将它添加到接口和模板类中,然后除非必要,否则不需要更新所有其他操作。