【问题标题】:Is this a good instance for the Decorator design pattern?这是装饰器设计模式的一个很好的例子吗?
【发布时间】:2012-05-01 21:01:14
【问题描述】:

所以我今天参加了计算机科学入门课程的考试。其中一个问题是关于装饰器设计模式的,它给我带来了一些麻烦。我的问题不是关于正确答案是什么,而是这是否是一个使用装饰器模式的好例子。为什么要装饰人员层次结构,因为它同样容易并且需要更少的类来让 Population 类直接计算人员的 BMI?既然 BMI 是 Person 对象状态的派生属性,那么装饰器真的会在这种情况下添加功能吗?

问题:

interface Person(){
    double getWeightInKG();
    double getHeightInMeters();
}

鉴于上面的人接口使用装饰器模式来实现下面定义的人口类。 BMI 的计算公式为 BMI = 体重(公斤)/身高(米)^2。您可能必须设计和实现其他类和接口来实现这一点。假设您使用了 java.util.ArrayList。

+ Population: 
    - public void addPerson(Person p);
    - public void removePerson(Person p);
    - public double getAverageBMI();
    - public Person[ ] getPeopleInBMIRange(double bmi_min, bmi_max);
    - public int populationSize(); 

【问题讨论】:

  • 因为“人口”是人的集合。它不是BMI计算器,也不应该是。我对在人群中开始使用特定于 BMI 的功能有点怀疑——这似乎更像是您要从人群中过滤出的信息。
  • @Dave,完全同意 BMI 特定功能不应该属于人口类别。
  • 我是一名 Java 教师,因此我了解创建使用设计模式的简单玩具领域作业的难度。 DP 根本不适合任何过于简单化的东西。

标签: java design-patterns decorator


【解决方案1】:

我不会使用装饰器模式来装饰人。我会创建一个单独的类来计算 BMI,如下所示:

class BMICalculator {
    double getBMI(Person person) {}
}

然后我会在 Population 类中使用 BMICalculator

class Population {
     private final BMICalculator calc;
     public double getAverageBMI() {
         double total = 0;
         for ( Person p : people ) {
            total += calc.getBMI(p);
         }
         return total/people.size();
     } 
}

我认为装饰器不适合这里。

【讨论】:

  • 所以我猜这会被称为Strategy
  • 这里不是真正的策略模式。这只是面向对象的编程,使用另一个对象来完成它所设计的工作。
  • 如果它不是策略,那么它甚至没有理由成为一个对象。在这种情况下,为什么不使用简单的静态方法?拥有一个对象的重点是动态调度,在这种情况下提供可插入的不同实现。
  • 你可以有一个静态方法,当然。一般来说,虽然这更难测试。如果你想模拟 BMI 计算器,那就更难了。
  • 既然这是一个玩具领域,我想这是一个公平的评论,因为我们每个人都可以将 BMI 计算器映射到现实世界中的其他东西。但是,如果您将它映射到一个计算某些东西的函数,那么就没有理由模拟它。
【解决方案2】:

这个想法是定义一个接口,例如BmiPerson extends Person { double bmi(); },然后将这些聚合到 Population。所以即使BmiPerson 扩展了Person,它仍然可以被实现为在其中包含另一个Person——一个装饰器。至少这是我能做到的最好的。这仍然没有多大意义,因为Population 接受Person 并且不知道BmiPerson 中的额外方法。

【讨论】:

  • 是的,确实如此 :) 我在你写评论时更新了答案。
  • 但是Population 类只能收集BmiPersons,假设Population BMI 方法需要访问该信息。
  • 看我的回答,我完全涵盖了这句话。不管怎样,我给了这个任务最好的机会。我真的不知道如何在那里更好地应用装饰器。
  • 是的,这就是我回答问题的方式,我只是认为使用这种特殊设计模式似乎是一种糟糕的方式。装饰器模式最好用于防止子类爆炸,但在这个特定示例中这似乎不是问题。
  • 当你想改变已经定义的方法的行为时,装饰器非常棒,而不是当你需要添加新方法的时候。例如 Java 的 IO API。
【解决方案3】:

这个问题是垃圾,(至少)有两个原因。

1. 您不能将装饰器模式应用于界面。这 该模式的目标是将新行为固定在某个基础上 功能。接口没有基本功能。

2. 该模式的另一点是您可以应用新的 逐个对象的功能。你永远不会有 Person 你不想计算谁的 BMI。

【讨论】:

    猜你喜欢
    • 2011-02-17
    • 2011-07-20
    • 1970-01-01
    • 2014-07-07
    • 2012-01-13
    • 2015-03-27
    • 1970-01-01
    • 2012-06-27
    • 2015-10-30
    相关资源
    最近更新 更多