生成器与装饰模式

bjs*_*123 37 oop design-patterns builder decorator

什么时候开始使用Builder模式?,

据说建造者模式适合比萨实例.

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

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

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

Phi*_*ter 43

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

在面向对象的编程中,装饰器模式是一种设计模式,允许动态地将新/附加行为添加到现有对象.

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

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

  • @bjs:是的,装饰者和建造者可以合理地组合,你的例子是一种可能性; 但是,它会导致复杂的设计和不太可读的代码.我只使用Builder + Decorator,如果我确定它实际上是项目所需要的,而不仅仅是我的"模式热"案例.考虑是否值得将"addChilli()"方法添加到基类,而不是构建一个完整的`ChilliDecorator`.(一如既往,没有正确答案.) (4认同)

Emi*_*l H 21

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

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

装饰器(175)动态地将附加职责附加到对象.装饰器为子类化提供了灵活的替代扩展功能.

注意强调装饰器.它是子类化的灵活替代方案.子类化用于建模is-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
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

Connection conn = DriverManger.getConnection(dsn);
Run Code Online (Sandbox Code Playgroud)

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


Rav*_*abu 7

让我们来看看BuilderDecorator的关键特性.

建造者 :(创作模式)

  1. 从客户端程序传递到可能容易出错的Factory类的参数太多
  2. 一些参数可能是可选的,与Factory强制发送所有参数不同
  3. 对象很重,它的创建很复杂.例如,建造各种类型的比萨饼

装饰者 :(结构模式)

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

何时使用装饰器:

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

回到您的查询:

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

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

例如:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
Run Code Online (Sandbox Code Playgroud)

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

将构建器保持在单独的类中(流畅的界面)

何时使用装饰器模式?