生成器与装饰模式

时间:2011-01-22 14:22:50

标签: oop design-patterns decorator builder

来自When would you use the Builder Pattern?

据说构建器模式适用于Pizza示例。

为什么不装饰师? 将奶酪,意大利辣香肠,培根作为基础披萨上的附加装饰品。

是否因为奶酪/意大利辣香肠必须单独建造。我不认为,它们需要单独构建,因为它们可以随时可用。

请澄清一下。 我也在寻找装饰模式的一个很好的现实世界的例子,以及为什么它适合那个特定的例子。谢谢。

4 个答案:

答案 0 :(得分:43)

来自维基百科的装饰模式文章:

  

在面向对象的编程中,   装饰图案是一种设计模式   允许新的/额外的行为   要添加到现有对象   动态。

在完全构建后,没有必要向披萨添加配料。你不要吃半个披萨,然后加一个披萨。

换句话说,Builder Pattern可以很容易地构建一个在构造时 的独立方向上可扩展的对象,而Decorator Pattern允许您向对象添加功能扩展。在施工时间之后。使用装饰器模式构造对象是不好的,因为它使对象处于不一致(或至少是不正确的)状态,直到所有必需的装饰器都到位 - 类似于使用setter指定可选构造函数参数的JavaBean问题。

答案 1 :(得分:21)

你混淆了两件截然不同的事情。 GoF将Builder分类为创建模式,而Decorator是结构模式。它们描述如下(Gamma等,第1页):

  

构建器(97)将复杂对象的构造与其表示分开,以便相同的构造过程可以创建不同的表示。

     

装饰器(175)动态地将附加职责附加到对象。 装饰器为子类化提供了一种灵活的替代方法,可用于扩展功能。

注意强调装饰器。它是子类化的灵活替代方案。子类化用于建模是-a 关系。奶酪不是披萨。披萨是由许多成分组成的 ,通常使用成分进行建模。

建造者模式在这里是相关的,因为有大量的成分需要以标准化的方式构建它们。

为了获得装饰器的真实示例,我最近想在我的java应用程序中记录使用jdbc执行的查询。我通过实现一个名为LoggingConnection的类来完成此操作,该类扩展了Connection接口。

public class LoggingConnection implements Connection
{
    public static class LogEntry
    {
        public String sql;
        public int invocationCount;
        public double avgTime;
        public double maxTime;
    }

    private Connection delegate;

    private Map<String, LogEntry> log;

    public LoggingConnection(Connection delegate)
    {
        this.delegate = delegate;
        this.log = new HashMap<String, LogEntry>();
    }

    public Map<String, LogEntry> getLog()
    {
        return log;
    }

    @Override
    public void clearWarnings()
    throws SQLException
    {
        delegate.clearWarnings();
    }

    @Override
    public void close()
    throws SQLException
    {
        delegate.close();
    }

    // forwarding declarations to all other methods declared in the interface
    ...
}

这允许我传递连接的具体实现,并在运行时扩展其功能。子类化在此上下文中会有问题,因为您不一定知道实际返回的连接对象。这是因为它是使用DriverManager工厂构建的:

Connection conn = DriverManger.getConnection(dsn);

在这种情况下,conn对象是驱动程序中包含的实现,我根本不知道它的名称。装饰器方法的责任在于我不必知道,并且它与特定实现无关。

答案 2 :(得分:7)

让我们了解 Builder Decorator 的主要特征。

Builder :(创作模式)

  1. 从客户端程序传递到可能容易出错的Factory类的参数太多
  2. 与Factory强制发送所有参数
  3. 不同,某些参数可能是可选的
  4. 对象很重,创建很复杂。例如建造各种比萨饼
  5. Decorator :(结构模式)

    1. 在运行时向对象添加行为。继承是实现此功能的关键,这是此模式的优点和缺点。
    2. 它增强了界面的行为。
    3. 装饰器可以看作只有一个组件的简并复合。但是,装饰器增加了额外的责任 - 它不是用于对象聚合。
    4. 装饰器支持递归合成
    5. 装饰器旨在让您在不​​进行子类化的情况下向对象添加职责
    6. 何时使用装饰器

      1. 应动态添加/删除对象职责和行为
      2. 具体实施应与责任和行为分离
      3. 当子分类成本太高而无法动态添加/删除职责时
      4. 回到您的查询:

        Builder 是Pizza的正确创作模式。披萨最初是用强制性成分制作的(面包等)。奶酪,意大利辣香肠,培根是可选配料,但在制作过程中它们仍然可以成为比萨饼的一部分。

        Decorator 对于在已创建的对象的运行时添加动态职责非常有用。

        e.g。 :

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
        

        有关详细信息,请参阅以下帖子:

        Keeping builder in separate class (fluent interface)

        When to Use the Decorator Pattern?

答案 3 :(得分:2)

构建器模式专门用于构建和装饰器以在构建后添加特殊功能。 例如,在上面的Pizza示例中,我们可以决定使用基于问题域的两种模式之一。

如果Chilli Flakes对于比萨饼来说是必不可少的,同样我们有很多成分可以添加到比萨饼中,其中很少有基本的比萨饼可以食用(有意义的状态),我们可以更喜欢使用Builder。 比萨饼一旦建成,我们可以用番茄酱,橄榄等不同的配料去装饰它......

此外,正确地说,它们可以一起使用,但这会增加复杂性。因此,只有在问题域中需要时才能明智地使用模式,否则简单的构造就足够了。