2011-06-25 58 views
8

我有一段代碼使用BigDecimal類,我討厭界面的笨拙。擴展BigDecimal?

我已經通過創建靜態方法具有以下方法輔助類緩解使用BigDecimal s的整數的疼痛:

compare(BigDecimal first, int second) 
divide(BigDecimal dividend, BigDecimal divisor, int scale) 
divide(BigDecimal dividend, int divisor, int scale) 
divide(int divident, int divisor, int scale) 
multiply(BigDecimal first, BigDecimal second, int scale) 
multiply(BigDecimal first, int second, int scale) 
multiply(int first, int second, int scale) 
zeroPad(BigDecimal value, int totalLength, int scale) 

這就是我需要現在的代碼是一個小更可讀比以前。但是,我讀到靜態方法是一個「壞」的東西,他們不遵循面向對象的原則。

但是,如果我擴展BigDecimal然而,我會定義一個新類型,因此我不得不重新定義所有方法來將它們與我的對象一起包裝,否則我將無法使用增強方法的結果。這似乎不是一件聰明的事情。

你會如何解決這個問題?

+0

有趣的是,我在代碼中製作了幾乎完全相同的靜態方法。對我來說,「BigDecimal」沒有內置的「細分(BigDecimal dividend,int divisor)」方法真是瘋狂。上次你什麼時候需要用小數除以任何東西?在我的任何代碼計算中,我除了'int'外沒有其他任何東西。 (不是說這些案例不存在,而是因爲除數似乎是標準庫中最值得包含的情況)。 – ryvantage

回答

5

我會盡力而爲!

這種類型的所有設計決定都必須基於希望讓代碼更易於維護,以便接下來的程序員接管後面的代碼。這就是爲什麼我們首先進行O-O設計和基於組件的開發。

但是考慮到Java的語法,爲基於數學的表達式創建API確實很困難。我有兩個問題與當前的BigInteger API:

  • 不是很接近平時的數學符號
  • 它是不對稱的對稱運營商如添加和乘

[操作符重載是C++的少數功能之一,我錯過了Java]

哪個更具可讀性?

BigInteger a = ...; 
BigInteger b = ...; 
BigInteger c = divide(a, b); 

BigInteger a = ...; 
BigInteger b = ...; 
BigInteger c = a.divide(b); 

就個人而言,我更喜歡第二個版本。

更糟糕的是,不同基本類型的數字是同一個表達式的一部分的情況。例如。

int a = ...; 
BigInteger b = ...; 
BigInteger c = divide(a, b); 

int a = ...; 
BigInteger b = ...; 
BigInteger c = BigInteger.valuOf(a).divide(b); 

也可以考慮在符號從微小變化在相應的數學符號上的巨大分歧:

  • (a-b)*c轉換爲a.subtract(b).multiply(c)multiply(subtract(a,b),c)
  • c*(a-b)被翻譯爲c.multiply(a.subtract(b))multiply(c,subtract(a,b))

對我來說,比純粹的基於O-O的表示法更容易編寫和讀取靜態方法表示法。

+0

我想這畢竟是最簡單的安全方法,因爲如果我打包BigDecimal,它將不再適用於JDBC。 – stivlo

4

不要擴展BigDecimal,使用它的包裝類(如你有的)或另一個框架如Commons Math。如果你創建一個繼承另一個類(即BigDecimal的你的情況)一類org.apache.commons.math.dfp.Dfp

+0

我會看看Dfp。所以一個包裝類將在我猜對象內部包含一個BigDecimal,並且由於與BigDecimal無關,我不得不重寫所有委託給BigDecimal的方法以及所有我的方法。這種方法怎麼會優越?這似乎與擴展BigDecimal的努力大致相同。只是想明白,我很樂意被證明是錯誤的。 – stivlo

+1

思考更多它會更好,因爲我不需要提供所有的方法,只需要我需要的方法,所以我不會混合MyBigDecimal和BigDecimal實例。 – stivlo

+0

org.apache.commons.math.dfp.Dfp的鏈接不再有效 –

0

,子類仍具有所有 -

Dfp類似於你想要什麼父級(超級)類的屬性。在你的情況,如果你寫:

public class UsableBigDecimal extends BigDecimal { 
... 
} 

任何UsableBigDecimal對象仍然是BigDecimal的情況,因爲這是他們的父類。您可以像使用任何BigDecimal對象一樣使用它們,包括您的靜態實用程序方法。

也就是說,在我看來,靜態實用方法在處理核心Java類時是非常可以接受的共享代碼。

+0

MyBigDecimal將是BigDecimal的一個實例,可以這樣使用,但不是相反的,所以如果我調用基類的方法派生類,它返回一個新的基類實例,我不能再使用派生類方法(除了複製構造函數,但會使代碼更笨拙)。 – stivlo

2

請問您可以向我澄清一下,「我要定義一個新類型,因此我必須重新定義所有方法來將它們與我的對象一起包裝,否則我將無法完成用增強方法使用結果。「?

  • 如果您需要使用從BigDecimal的API的方法,再加上自己的其他方法,那麼我建議你繼承BigDecimal的自定義類。通過這種方式,您無需爲已經適合您的BigDecimal方法定義包裝器。這種情況下,您的自定義類 BigDecimal,此外還有更多。

  • 如果你只需要一個幾個從BigDecimal的API的方法,再加上自己的其他方法,那麼我建議你從BigDecimal的派生。而是你內部使用一個BigDecimal,而你委託它爲你的自定義API公開的一些功能。這種情況下,您的自定義類有一個 BigDecimal,但它不是BigDecimal。

然後爲了包裝一個BigDecimal方法,來回報您的自定義類型:

隨着inhertance,你會做類似如下:

@Override public MyBD divide(int second) 
{ 
    return new MyBD(this.divide(second)); 
} 

隨着代表團(即組成) ,你會怎麼做:

public MyBD divide(int second) 
{ 
    return new MyBD(_innerBigDecimal.divide(second)); 
} 

使用靜態輔助方法,你會怎麼做:

public static BigDecimal divide(BigDecimal first, int second) 
{ 
    return first.divide(second); 
} 
+0

例如,如果我定義MyBigDecimal擴展BigDecimal,如果我使用基類中定義的方法它將返回一個BigDecimal,因此這樣的代碼將不起作用: new MyBigDecimal(「12.89」)。divide(AnotherBigDecimal).methodOfMyBigDecimal () – stivlo

+0

好吧,明白了。所以是的,你應該用你自己的版本來包裝你需要的原始BigDecimal方法。只要注意,這個_wrapping job_必須完成你選擇的任何選擇,不管它是繼承,委託,還是你正在做的靜態輔助函數! – superjos

+0

我在你的評論後更新了答案 – superjos

-4

我會忘記這個問題,和原來的問題,並習慣BigDecimal的API,因爲它是。正如這個問題的存在表明的那樣,你所做的只是爲自己創造問題。

+0

假設我想用固定格式顯示所有小數,理想情況下我會覆蓋toString。這樣做的自然方式是擴展BigDecimal,但它也需要重寫它的構造函數,因此我更願意包裝它。 –

+0

@LluisMartinez實現這一點的自然方法實際上是編寫一個新的Format類。 'toString()'只是一個調試玩具。 – EJP