2013-09-27 19 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包依赖于接口。