【问题标题】:How to get rid of instanceof in this Builder implementation如何在此 Builder 实现中摆脱 instanceof
【发布时间】:2012-08-03 09:26:22
【问题描述】:

想法

我需要创建命令。命令可以配置参数。 并非每个命令都可以接收相同的参数。所以有些不得不被忽略。

我有一个抽象类 Command,我在其中定义了一个 Builder。默认情况下,每个附加参数都会抛出 'UnsupportedOperationException'

public abstract class Command {

   public static abstract class CommandBuilder {

        // TODO instanceof. How to do this better?
        public CommandBuilder append(Parameter p)
            throws UnsupportedOperationException {

            if (p instanceof URLParameter)
                return append((URLParameter) p);

            if (p instanceof ActionParameter)
                return append((ActionParameter) p);

            if (p instanceof RepeatParameter)
                return append((RepeatParameter) p);

            if (p instanceof TimeOutParameter)
                return append((TimeOutParameter) p);

            return this;

        }

        public CommandBuilder append(URLParameter p)
                throws UnsupportedOperationException {

                    throw new UnsupportedOperationException(
                        "URLParameter not applicable");

        }

        public CommandBuilder append(RepeatParameter p)
            throws UnsupportedOperationException {

                throw new UnsupportedOperationException(
                    "RepeatParameter not applicable");

            }
            ...

}

如果您希望参数适用于某个具体的命令,可以说是 FTPCommand。

你必须这样做:

public class FTPCommand extends Command {

    public static class Builder extends CommandBuilder {

    @Override
    public CommandBuilder append(URLParameter p) {
            System.out.println("URLParemeter appended");
                return this;
            }
        }

}

因此,当提供 URLParameter 时,它不会再抛出异常而是应用它。

但是这个 CommandBuilder 的客户端可能无法提供具体的子类。所以通常给出一个“参数”。但它需要去正确的地方(方法)

就像一个 URLParameter 必须到达append(UrlParameter p)

我怎样才能以干净(er)和漂亮(r)的方式做到这一点?因为我对使用 instanceof 并不是很“热情”。

【问题讨论】:

    标签: java oop design-patterns instanceof


    【解决方案1】:

    这看起来像是经典的 double-dispatchvisitor 场景。来自双重调度参考:

    一种将函数调用分派到不同混凝土的机制 函数取决于所涉及的两个对象的运行时类型 通话

    ParameterCommandBuilder 需要在它们之间进行交互以决定做什么。

    CommandBuilder 可以回调参数。 Parameter 对象都实现了一个公共接口,每个子类的实现会有所不同。

    public CommandBuilder append(Parameter p) {
       // the append method called depends on the underlying type of 'p'
       p.append(this);
    }
    

    【讨论】:

    • 酷。所以像这样:public class URLParameter extends Parameter { @Override public void append(Command.CommandBuilder builder) { builder.append((URLParameter) this); } }
    • 看起来不无道理。您的 CommandBuilder 子类决定了在 Parameter 上调用什么,而您的 Parameter 子类决定了调用时会发生什么(我总是必须停下来认真思考在这些情况下发生了什么——这并不完全直观!)
    • 我忘了在我的问题中提到将来可能必须引入新参数。那么它仍然是这样做的好方法吗?或者有没有更好的办法stackoverflow.com/questions/11793720/…
    • 如果您添加新参数,您只需实现关联的 dinterface。因为您使用方法分派来确定调用什么,所以一切都应该正常工作。您不必编辑 switch 或 if/else if 子句,因此一切都很好
    • 所以在你看来。每次创建新的 ConcreteParameterClass 时都必须在 de CommandBuilder 中创建新的 append(ConcreteParameter) 方法,这不是很糟糕吗?
    【解决方案2】:

    我会在你的界面中添加一个访问者方法

    interface Parameter {
        public void append(CommandBuilder builder);
    }
    
    class CommandBuilder {
        public CommandBuilder append(Parameter p) {
           p.append(this);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-11
      • 2012-07-06
      • 1970-01-01
      • 1970-01-01
      • 2020-02-26
      • 2023-04-03
      相关资源
      最近更新 更多