【问题标题】:Design Pattern to Handle Grouping Similar Entities Together处理将相似实体分组在一起的设计模式
【发布时间】:2009-09-16 16:28:02
【问题描述】:

在过去的几年里,我参与的项目中,我们在对象层次结构中遇到了类似的问题,似乎总是会导致问题。我很好奇这里是否有人知道可以优雅地处理这种情况的经典 OOP(Java、C#、PHP5 等)设计模式。

假设我们有一个现有的系统。除其他外,该系统具有两种类型的实体,每种实体都使用单独的类进行建模。比方说

  1. 客户

  2. 销售代表

由于历史原因,这些类都不是从同一个基类继承的,也不是共享一个公共接口。

我看到的问题是,不可避免地,需要我们将 Customer 和 SalesRepresentative 视为同一类型的对象的新功能。我过去看到的处理方式是创建一个新类,其中包含两者的成员变量,然后每个方法将对对象进行不同的操作,具体取决于设置的对象

//pseudo PHPish code
class Participator
{
    public $customer;
    public $salesRepresentative;

    public function __construct($object)
    {
        if(object is instance of Customer)
        {
            $this->customer = $object;
        }

        if(object is instance of SalesRepresentative)
        {
            $this->salesRepresentative = $object;
        }           
    }

    public function doesSomething()
    {

        if($customer)
        {
            //We're a customer, do customer specific stuff
        }
        else if($salesRepresentative)
        {
            //We're a salesRepresentative, do sales 
            //representative specific stuff
        }           
    }
}

有没有更优雅的方式来处理这种情况?

【问题讨论】:

    标签: c# java php design-patterns oop


    【解决方案1】:

    也许可以在这里使用 Wrapper。创建一个 Wrapper 接口,比如 ParticipatorWrapper,指定新功能并为每个类构建具体的 Wrapper,比如 CustomerWrapper 和 SalesRepresentativeWrapper,它们都实现了新功能。

    然后简单地将对象包装在其适当的包装器中并编写针对 ParticipatorWrapper 的代码。

    更新:Java 代码:

    interface ParticipatorWrapper{
        public void doSomething();
    }
    
    class CustomerWrapper implements ParticipatorWrapper{
        Customer customer;
        public void doSomething(){
           //do something with the customer
        }
    }
    
    class SaleREpresentativeWrapper implements ParticipatorWrapper{
        SaleRepresentative salesRepresentative;
        public void doSomething(){
           //do something with the salesRepresentative
        }
    
    }
    
    class ClientOfWrapper{
        public void mymethod(){
             ParticipatorWrapper p = new ParticipatorWrapper(new Customer());
             p.doSomething();
       }
    }
    

    【讨论】:

    • +1 与 OP 的建议类似的逻辑,但比每个方法中的 if/else 块更容易阅读和维护。如果您直到运行时才知道类型,则可能与静态工厂方法结合使用。
    • +1 - 但您需要添加工厂以创建适当的 ParticipatorWrapper,或者更改新的 ParticipatorWrapper(new Customer()) 行以创建 CustomerWrapper。
    【解决方案2】:

    这是文森特答案的替代方案,采用相反的方法。正如我在下面指出的那样,存在一些缺点,但您的具体问题可能会消除这些缺点,我认为这种解决方案在这些情况下更简单(或者您可能希望使用此解决方案和文森特的某种组合)。

    不是包装类,而是在类中引入钩子,然后将函数传递给它们。如果您希望对来自两个类的相同数据执行相同的操作,这是一个合理的选择(我猜您是这样,基于感叹这两个类没有共享的超类)。

    这是使用Visitor 而不是Wrapper。 Javaish 这类似于:

    public <Output> Output visit(Vistor<Output> v) {
    return v.process(...all shared the fields in Customer/SalesRep...);
    }
    

    然后你有一个访问者接口,你的所有函数都继承自它,如下所示:

    interface Visitor<Output> {
    public Output process(...shared fields...);
    }
    

    有一些方法可以砍掉传递给访问者的内容,但这涉及引入新类来指定要使用的输入,无论如何这都会变成包装,所以你不妨使用文森特的答案。

    此解决方案的缺点是,如果您做一些改变类字段结构的事情,您可以为自己购买大量重构,这在文森特的回答中不是问题。如果您要对存储在 Customer/SalesRep 实例中的数据进行修改,此解决方案的用处也会有所降低,因为您实际上必须将这些数据包装在 Visitor 中。

    【讨论】:

    • 哦,这还假设您可以对遗留类进行修改。我假设您不是因为其他现有依赖项而进行重构,而不是因为不允许您这样做,这会排除我的解决方案。
    • +1 了解更多信息,因为我主要对了解可以解决问题的各种设计模式感兴趣。当您生活在 PHP 领域时,您不会接触到很多现实世界的示例。
    【解决方案3】:

    我认为您可以将mixins 的概念应用到您的类中以获得您想要的功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-22
      • 2015-12-01
      • 2023-03-11
      • 1970-01-01
      • 2015-04-18
      • 1970-01-01
      • 1970-01-01
      • 2020-08-23
      相关资源
      最近更新 更多