【问题标题】:Code reusing with anonymous class in JavaJava中匿名类的代码重用
【发布时间】:2015-10-08 08:48:01
【问题描述】:

Java 7

我有如下界面:

public interface SqlOperator{

    public String apply(Object o);

    /**
    * @return an operator representing the set defined 
    * by inversing the image of {@this operator}.
    */
    public SqlOperator not();

    //Some other methods
}

我有一些类似的实现:

public class Foo implements SqlOperator{

    public SqlOperator not(){
        return new Foo(){
            @Override
            public String apply(Object o){
                return String.format("NOT (%s)", super.apply(o));
            }
        };
    }

    //other methods implementation
}

还有这个

public class Bar implements SqlOperator{

    public SqlOperator not(){
        return new Bar(){
            @Override
            public String apply(Object o){
                return String.format("NOT (%s)", super.apply(o));
            }
        };
    }

    //other methods implementation
}

问题是 not() 方法对于现在的所有实现几乎相同(目前我有 7 个),除了要使用 new 运算符实例化的类。有没有办法在我需要实现SqlOperator 的任何时候避免编写这样的样板代码。

【问题讨论】:

  • 你用的是什么java版本?
  • 我可以建议not(foo)foo.not() 更好的API - 使用组合来构建你的表达式会更好。它还使实现andor 运算符更容易:and(foo, bar) 而不是foo.and(bar) 等。这意味着您的SqlOperator 接口将只包含apply 方法。
  • @AndyTurner 好吧,我考虑过了。但是 not 方法是特定于操作符的。

标签: java code-reuse anonymous-class


【解决方案1】:

在 Java-8 之前的时代,标准选项是创建一个像 AbstractSqlOperator implements SqlOperator 这样的抽象类,它定义了具有一些标准实现的方法。然后具体实现扩展这个抽象类,而不是直接实现接口。

Java-8 引入了一种使用默认方法的新方法:

public interface SqlOperator{

    public String apply(Object o);

    /**
    * @return an operator representing the set defined 
    * by inversing the image of {@this operator}.
    */
    default public SqlOperator not() {
        return new SqlOperator(){
            @Override
            public String apply(Object o){
                return String.format("NOT (%s)", SqlOperator.this.apply(o));
            }

            @Override
            public SqlOperator not() {
                // double not: just return the original operator
                return SqlOperator.this;
            }
        };
    }

    //Some other methods
}

【讨论】:

  • 嗯,接口不知道SomeImplementation
  • @St.Antario,它可以自己实现。查看更新的答案
  • 想要堆栈异常吗?正如你从 apply 中申请的那样?
  • @DamianLeszczyński-Vash,我称申请不同的对象(外部实例)。试试看,效果不错。
【解决方案2】:

将您的 SqlOperator 接口包装在一个抽象类中。然后让您的 SomeImplementation 类从抽象类继承。抽象类将实现接口 not() 方法。

public abstract class AbstractImplementation implements SqlOperator
{
    public SqlOperator not(){
    return new SomeImplementation(){
        @Override
        public String apply(Object o){
            return String.format("NOT (%s)", super.apply(o));
        }
    };
}

//...
public class SomeImplementation extends AbstractImplementation
{
    //... your stuff here
}

【讨论】:

    【解决方案3】:

    你有很多选择。

    如果您使用的是 Java8,则可以在 SqlOperator 接口中创建一个 default 方法,而无需跨子类实现它:

    public interface SqlOperator{
        public default SqlOperator not() {
            return new SomeImplementation(){
                @Override
                public String apply(Object o){
                    return String.format("NOT (%s)", super.apply(o));
                }
            };
        }
    }
    

    但是,如果您还没有升级到 Java8,那么您可以只引入 SqlOperatorabstract 子类,您将在其中拥有 not() 实现,然后所有其他实现者都可以扩展这个抽象类。例如:

    public abstract class AbstractSqlOperator implements SqlOperator {
        public SqlOperator not() {
            return new SomeImplementation(){
                @Override
                public String apply(Object o){
                    return String.format("NOT (%s)", super.apply(o));
                }
            };
        }
    }
    
    public class SomeImplementation extends AbstractSqlOperator { ... }
    

    【讨论】:

    • 你不能看看更新后的问题吗?我相信我并不清楚我真正想要什么......
    • 是的。然后使用 abstract 类的方法(包含共享的 not() 实现)将适合您的情况。
    【解决方案4】:

    恕我直言,您在克隆代码时遇到了一些设计问题。已经提出了基于继承的解决方案,我宁愿进行组合。

    目标是创建一个否定其他运算符的 SqlOperator。

    我会从 SqlOperator 接口中删除 not()。每个运营商都应该分开。 NOT,LIKE,AND,OR是SQL中对表达式进行操作的运算符。自然,运算符 AND 不应该知道如何否定它。

    public interface SqlOperator{
        public String apply(Object o);
    }
    
    class NotOperator implements SqlOperator {
    
        private final SqlOperator operator;
    
        NotOperator(SqlOperator operator) {
           this.operator = operator;
        }
    
        public String apply(Object o) {
            return String.format("NOT (%s)", operator.apply(o));
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-06
      • 1970-01-01
      • 1970-01-01
      • 2018-08-25
      • 1970-01-01
      相关资源
      最近更新 更多