如何通过向Java中现有的库类添加方法来创建新类?

时间:2013-11-20 17:37:58

标签: java oop design-patterns inheritance composition

我正在尝试为Java的BigDecimal添加一些便捷方法,并创建一个CustomBigDecimal类。 说我想添加一个方法reciprocal()。 我尝试使用以下继承方式执行此操作:

public class CustomBigDecimal extends BigDecimal
{
   .....
   .....
   public CustomBigDecimal reciprocal()
   {
       .....
   }       
}

CustomBigDecimal foo1 = new CustomBigDecimal(1);
CustomBigDecimal foo2 = new CustomBigDecimal(2);
CustomBigDecimal foo2 = foo1.add(foo2); //cannot cast superclass to subclass

这种方法的问题在于我无法将超类强制转换为子类(出于我非常清楚的原因)。并且超类的所有方法都返回一个BigDecimal。 我已经想到了使用如下方法解决这个问题的解决方案:

public class CustomBigDecimal 
{
    private BigDecimal val;
    CustomBigDecimal(BigDecimal val)
    {
       this.val = val;
    } 
    ......
    ......  
    public CustomBigDecimal add(CustomBigDecimal augend)
    {
        return new CustomBigDecimal(val.add(augend.getBigDecimal()));
    }       
    .....
    .....
    public CustomBigDecimal reciprocal()
    {
        ....
    } 
}

但是如果我采用第二种方法,我必须编写BigDecimal的每个方法。

有没有更好的方法来解决这个问题?

6 个答案:

答案 0 :(得分:4)

如果您实际上没有更改BigDecimal本身的表示形式,并且只是添加了一些辅助方法,那么您可以使用另一个静态包含辅助方法的类。即

class BigDecimalMethods{
     public static BigDecimal reciprocal(BigDecimal bd){
     }
     //etc
}

答案 1 :(得分:1)

忘记继承。它会强制您处理CustomBigDecimal和非自定义BigDecimal

想象一下,如果你想为toProperCase()类添加一个方便的String方法,你会怎么做(这是一个非常常见和频繁的问题)。您将被迫创建StringUtils类,因为String类是final。缺点是,您需要使用StringUtils.toProperCase(someString)而不是someString.toProperCase()

如果String类不是final,您可以创建一个子类并在那里添加方法。但是这很糟糕,你仍然无法做someString.toProperCase(),你需要这样的东西:

if (!(someString instanceof MyStringSubclass)) {
    someString = new MyStringSubclass(someString);
}
String somethingElse = ((MyStringSubclass) someString).toProperCase();

而且,那段代码确实太可怕了。在CustomBigDecimal课程中,您遇到了同样的问题:

if (!(someBigDecimal instanceof CustomBigDecimal)) {
    someBigDecimal = new CustomBigDecimal(someBigDecimal);
}
CustomBigDecimal somethingElse = ((CustomBigDecimal) someBigDecimal).reciprocal();

而且,那种代码很糟糕。

在ruby,javascript和其他一些语言中,您可以 mixin 将一些新方法添加到现有类中,而无需更改它。这将是解决问题的正确方法。不幸的是,java不允许这样做。因此,更好的解决方案是utils方法:

public class BigDecimalUtils {
    private BigDecimalUtils() {}

    public static BigDecimal reciprocal(BigDecimal a) {
       ...
    }
}

utils方法是一种反模式,但由于无法将方法混合到现有的java类中,因此这是最好的方法。使用子类仍然是一个更糟糕的反模式。正确的解决方案是将mixins添加到java语言中,但这当然不是一种选择。

注意:我没有考虑改变JDK rt.jar文件中实际类的选项,也没有考虑使用字节码操作类加载器来模拟它。这对此非常严重。

答案 2 :(得分:0)

你可以这样做:

CustomBigDecimal foo1 = new CustomBigDecimal(1);
CustomBigDecimal foo2 = new CustomBigDecimal(2);
CustomBigDecimal foo3 = new CustomBigDecimal(foo1.add(foo2).intValue());
    // Or floatValue()...

答案 3 :(得分:0)

您必须实现一个辅助静态方法或类似的构造函数:

public CustomBigDecimal(BigDecimal bigDecimal) {
    super(bigDecimal.toString());
}

CustomBigDecimal foo2 = new CustomBigDecimal(foo1.add(foo2));

答案 4 :(得分:0)

  

但是如果我采用这种方法,我必须实现每一种方法   BigDecimal的。

我认为你不需要实现所有方法。可能是每个构造函数:

class CustomBigDecimal extends BigDecimal
{

    public CustomBigDecimal(BigInteger val) {
        super(val);
    }

    public CustomBigDecimal(int i)
    {
        super(String.valueOf(i));
    }

    public CustomBigDecimal(String str)
    {
        super(str);
    }
    public CustomBigDecimal(BigDecimal bigDecimal)
    {
       this(bigDecimal.toString());   
    }

   CustomBigDecimal foo1 = new CustomBigDecimal(1);
   CustomBigDecimal foo2 = new CustomBigDecimal(2);
   CustomBigDecimal foo3 = new CustomBigDecimal(foo1.add(foo2).toString());
   CustomBigDecimal foo4 = new CustomBigDecimal(foo1.add(foo2));

}

答案 5 :(得分:0)

Vandale的答案是最好的解决方案。但是,如果你真的想这样做,只需“覆盖”返回BigDecimal的BigDecimal方法

public CustomBigDecimal abs() {
    return new CustomBigDecimal(super.abs());
}

问题在于,所有新的CustomBigDecimal返回方法都不会实际覆盖BigDecimal的版本,并且您需要覆盖每个构造函数(有很多),以及额外的CustomBigDecimal(BigDecimal abs)

你可以看到这是多么混乱,为什么我认为你应该采用Vandale的答案