2013-09-27 42 views
1

在Java API的設計,我想出了下面的模式來滿足這裏列出這裏有什麼設計模式嗎?這個java代碼有沒有可能的缺陷?

  • 實際的公共API類應實現爲final類有一定的要求,以防止繼承和可能濫用
  • 實際的公共API類不應暴露超過所需方法的任何內容。
  • 分離API類和內部實現成不同的包
  • 範圍爲在公共和內部類的可擴展性或進化

示例代碼如下:

package external; 

import internal.AbstractProduct; 

public final class Product extends AbstractProduct{ 

    protected Product(int a, int b){ 
     super(a,b); 
    } 

    @Override 
    public int result(){ 
     return super.result(); 
    } 
} 

public class ProductFactory { 
    public static Product createProudct(int a, int b){ 
     return new Product(a, b); 
    } 
} 

和內部類如下:

package internal; 

public abstract class AbstractProduct { 

    private final AbstractProduct impl; 

    protected AbstractProduct(int a, int b){ 
     impl = new ProductImpl(a, b); 
    } 

    protected AbstractProduct(){ 
     impl = null; 
    } 

    protected int result(){ 
     return impl.result(); 
    } 
} 

class ProductImpl extends AbstractProduct{ 

    private int a; 
    private int b; 

    ProductImpl(int a, int b){ 
     this.a = a; 
     this.b = b; 
    } 

    @Override 
    protected int result(){ 
     return a*b; 
    } 
} 

Althoug它工作正常,並且具有適當的訪問級別,但是我只具有設計模式或API設計的初級水平技能,所以我很難用它來發現可能的故障。那麼這有什麼問題嗎?或者它是否已經實行了一些模式?

+1

http://codereview.stackexchange.com –

+0

謝謝@sᴜʀᴇsʜᴀᴛᴛᴀ,不知道「代碼審查」。那麼我應該刪除並重新發布在CR還是什麼? – cpz

+1

IMO不應該刪除這個問題。除了基本的非靈活工廠方法模式外,您的設計非常奇怪。爲什麼要把'AbstractProduct impl'標記爲'final'?看起來你想實現[裝飾](http://en.wikipedia.org/wiki/Decorator_pattern)。 –

回答

0

爲什麼要這樣做?

protected AbstractProduct(){ 
    impl = null; 
} 

當調用result()時,這將導致NullPointerException。

我也沒有看到AbstractProductProductImpl的觀點。只需將代碼放入Product即可。

我也會質疑爲什麼你需要一個ProductFactory如果只有一個實現,但如果你打算有未來的實現,那麼它會好的。

+0

是的,有可能爲'產品'的未來實現。所以工廠沒問題。 '產品'是我必須提供javadoc的API的一部分,所以爲了保持它乾淨和最小化,我只是想在產品中實際需要的方法。 'AbstractProduct'是'Product'和'ProductImpl'之間的內部通用契約。而且這樣我可以靈活地添加/刪除'ProductImpl'中的內部方法來進化或擴展。 – cpz

+0

您可以在'Product'中有內部方法,它們不會成爲公共API的一部分,只是讓它們變爲私有方法。然後當使Javadoc設置爲只爲公共方法創建HTML。我只是擔心你過於複雜的事情。如果您還沒有閱讀過,我推薦Jaroslav Tulach的_Practical API Design_,它涵蓋了這個主題。 – dkatzel

+0

我同意這種過度複雜化,但是如果我擁有'Product'中的所有內容,那麼將會以某種方式影響可擴展性或演化?並且在我的設計的情況下,整體API設計的可擴展性或演進具有優勢。我最近拿到了那本書,並沒有完全通過它,但似乎很難一次考慮所有的事情並且適應這個項目: -/ – cpz

4

您嘗試實施的唯一設計模式是Factory Method,其類別爲ProductFactory。這是唯一的設計模式崇拜者。

因爲你當前的代碼是非常不靈活,整個甚至可以被視爲anti-pattern,更具體:

  • Poltergeist,因爲Product只存在執行ProductImpl#result
  • Call super,因爲Product只使用super調用。
  • Accidental complexity,即使這個過程比一個簡單的int乘法。
  • Cargo cult,因爲你還沒有意識到爲什麼以及何時使用設計模式。

(甚至更多......)

說明:您的工廠方法模式是非常不靈活。需要注意的是Product類是public,但有一個protected構造函數(甚至標記爲final類,這是:爲什麼要對可以永遠繼承一個類protected方法?),這意味着ProductFactory至少應該與Product相同。


正如我在其他直接評論你的問題指出,如果你解釋的功能要求收到你的設計更好,更準確的幫助會很大。


IMO爲了瞭解設計模式,它會更好地去現實世界的例子,而不是繼續閱讀關於他們越來越多在​​網上,然後開始練習。我強烈建議從BalusC(Java和Java EE專家)這個Q/A:Examples of GoF Design Patterns in Java's core libraries

+0

好吧,我想我需要一些時間來解釋,我很難解釋的東西。也將嘗試詳細列出功能要求。 – cpz

+0

並感謝您指出反模式!順便說一句'ProductFactory'確保在同一個包中,儘管到目前爲止工廠無法控制'Product'的創建,但是將來可能會有這麼簡單的工廠。 – cpz

+0

@cpz答案編輯以包含Java SE和Java EE中設計模式的真實世界示例。 –

0

如果是我,我會打破它是這樣的:

package external; 

import internal.InternalProduct; 
import internal.ProductImpl; 

public final class Product { 

    private final InternalProduct internalProduct; 

    Product(final InternalProduct internalProduct) { 
     this.internalProduct = internalProduct; 
     assert this.internalProduct != null; 
    } 

    public int result() { 
     return this.internalProduct.result(); 
    } 
} 

public class ProductFactory { 
    public static Product createProduct(final int a, final int b) { 
     return new Product(new ProductImpl(a, b)); 
    } 
} 

隨着面向內部的包裝內容如:

package internal; 

public interface InternalProduct { 
    int result(); 
} 

public final class ProductImpl implements InternalProduct { 

    private final int a; 
    private final int b; 

    public ProductImpl(final int a, final int b) { 
     this.a = a; 
     this.b = b; 
    } 

    @Override 
    protected int result() { 
     return a * b; 
    } 
} 

你並不需要一個抽象類,你肯定不想Product擴展它。你應該在這裏使用封裝。這可以保護您的Product類免受更改爲內部接口的影響 - 除非您選擇方法,否則可以在沒有Product的情況下添加方法。

如果結束了更多的實現並且你想要一個抽象的父節點,你可以選擇每個實現是否擴展它,因爲你的external包依賴於接口。