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

时间:2022-09-11 20:54:46

I am trying to add some convenience methods to Java's BigDecimal and create a CustomBigDecimal class. Say I want to add a method reciprocal(). I have tried doing this with inheritence as follows:

我试图为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

The problem with this approach is that I cannot cast a superclass to subclass (for reasons I am well aware of). And all the methods of the superclass return a BigDecimal. I have thought of a solution to solve this using composition as follows:

这种方法的问题是我不能将超类强制转换为子类(出于我很清楚的原因)。并且超类的所有方法都返回一个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()
    {
        ....
    } 
}

But if I go with the second approach, I have to write every method of BigDecimal.

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

Is there a better approach to solve this problem?

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

6 个解决方案

#1


4  

If you aren't actually changing the representation of BigDecimal itself, and are just adding some helper methods, then you can have another class that contains your helper methods statically. ie

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

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

#2


1  

Forget about inheritance. It will force you to handle both CustomBigDecimals and non-custom BigDecimals.

忘记继承。它将强制您处理CustomBigDecimals和非自定义BigDecimals。

Imagine what you would do if you wanted to add a convenience toProperCase() method to the String class (and this is a very common and frequent issue). You would be forced to create a StringUtils class, because the String class is final. The downside is that then you will need to use StringUtils.toProperCase(someString) instead of someString.toProperCase().

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

If the String class was not final, you could create a subclass and add the method there. But this would sucks, you still could not do someString.toProperCase(), you would need something like:

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

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

And, that code is indeed horrible. In your CustomBigDecimal class, you hit the same issue:

并且,该代码确实很糟糕。在CustomBigDecimal类中,您遇到了同样的问题:

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

And again, that sort of code sucks.

而且,那种代码很糟糕。

In ruby, javascript and some other languages, you could mixin some new method into an existing class without having to alter it. This would be the correct solution for the problem. Unfortunately, java does not allows this. So, the better solution is the utils approach:

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

public class BigDecimalUtils {
    private BigDecimalUtils() {}

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

The utils approach is an anti-pattern, but since there is no way to mixin a method into an existing java class, it is the best approach to do. Using a subclass is still a worse anti-pattern. The correct solution would be to add mixins to the java language, but this is of course not an option.

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

Note: I am not considering options regarding in altering the actual classes in the JDK's rt.jar file, nor to emulate that with bytecode-manipulating classloaders. That would be a serious overkill for this.

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

#3


0  

You could do something like this:

你可以这样做:

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

#4


0  

You will either have to implement a helper static method or a constructor like so:

您将要么必须实现辅助静态方法或构造函数,如下所示:

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

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

#5


0  

But if I go with this approach, I have to implement every method of BigDecimal.

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

I don't think you will need to implement every method. Rather probably every constructor:

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

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));

}

#6


0  

Vandale's answer is the best solution. However, if you really wanted to do this, just "override" the methods of BigDecimal that return a BigDecimal

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

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

The problems with this are that all of your new CustomBigDecimal-returning methods won't actually override BigDecimal's version, and that you'll need to override every constructor (there are a lot), plus an extra CustomBigDecimal(BigDecimal abs)

这样做的问题是所有新的CustomBigDecimal返回方法都不会实际覆盖BigDecimal的版本,并且你需要覆盖每个构造函数(有很多),加上一个额外的CustomBigDecimal(BigDecimal abs)

You can hopefully see how messy this is, and why I think you should go with Vandale's answer

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

#1


4  

If you aren't actually changing the representation of BigDecimal itself, and are just adding some helper methods, then you can have another class that contains your helper methods statically. ie

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

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

#2


1  

Forget about inheritance. It will force you to handle both CustomBigDecimals and non-custom BigDecimals.

忘记继承。它将强制您处理CustomBigDecimals和非自定义BigDecimals。

Imagine what you would do if you wanted to add a convenience toProperCase() method to the String class (and this is a very common and frequent issue). You would be forced to create a StringUtils class, because the String class is final. The downside is that then you will need to use StringUtils.toProperCase(someString) instead of someString.toProperCase().

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

If the String class was not final, you could create a subclass and add the method there. But this would sucks, you still could not do someString.toProperCase(), you would need something like:

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

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

And, that code is indeed horrible. In your CustomBigDecimal class, you hit the same issue:

并且,该代码确实很糟糕。在CustomBigDecimal类中,您遇到了同样的问题:

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

And again, that sort of code sucks.

而且,那种代码很糟糕。

In ruby, javascript and some other languages, you could mixin some new method into an existing class without having to alter it. This would be the correct solution for the problem. Unfortunately, java does not allows this. So, the better solution is the utils approach:

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

public class BigDecimalUtils {
    private BigDecimalUtils() {}

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

The utils approach is an anti-pattern, but since there is no way to mixin a method into an existing java class, it is the best approach to do. Using a subclass is still a worse anti-pattern. The correct solution would be to add mixins to the java language, but this is of course not an option.

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

Note: I am not considering options regarding in altering the actual classes in the JDK's rt.jar file, nor to emulate that with bytecode-manipulating classloaders. That would be a serious overkill for this.

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

#3


0  

You could do something like this:

你可以这样做:

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

#4


0  

You will either have to implement a helper static method or a constructor like so:

您将要么必须实现辅助静态方法或构造函数,如下所示:

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

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

#5


0  

But if I go with this approach, I have to implement every method of BigDecimal.

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

I don't think you will need to implement every method. Rather probably every constructor:

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

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));

}

#6


0  

Vandale's answer is the best solution. However, if you really wanted to do this, just "override" the methods of BigDecimal that return a BigDecimal

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

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

The problems with this are that all of your new CustomBigDecimal-returning methods won't actually override BigDecimal's version, and that you'll need to override every constructor (there are a lot), plus an extra CustomBigDecimal(BigDecimal abs)

这样做的问题是所有新的CustomBigDecimal返回方法都不会实际覆盖BigDecimal的版本,并且你需要覆盖每个构造函数(有很多),加上一个额外的CustomBigDecimal(BigDecimal abs)

You can hopefully see how messy this is, and why I think you should go with Vandale's answer

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