这有什么设计模式吗?这个java代码有任何可能的缺陷吗?

时间:2013-09-27 04:52:20

标签: java oop design-patterns api-design

为了在java中设计API,我提出了以下模式来满足这里列出的某些要求

  • 实际公共API类应该作为最终类实现,以防止继承和可能的滥用
  • 实际公共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;
    }
}

虽然它工作正常并且具有适当的访问级别,但我只具有设计模式或API设计的初级技能,所以我似乎很难发现可能的故障。那么这有什么问题吗?还是一些已经实践过的模式?

3 个答案:

答案 0 :(得分:4)

您尝试实施的唯一设计模式是ProductFactory类中的Factory Method。这是唯一想要的设计模式。

由于您当前的代码非常不灵活,整体甚至可以被视为anti-pattern,更具体地说:

  • Poltergeist,因为只有Product才能执行ProductImpl#result
  • Call super,因为Product仅使用super次来电。
  • Accidental complexity,即使该过程不仅仅是一个简单的int乘法。
  • Cargo cult,因为您还没有意识到为什么以及何时使用设计模式。

(可能更多......)

说明:您的工厂方法模式非常不灵活。请注意Product类是public,但有一个protected构造函数(甚至标记为final类,奇数:为什么要{ {1}}类上的方法可以从不继承?),这意味着protected至少应与ProductFactory位于同一个包中。


正如我在其他评论中直接提到的那样,如果您解释功能要求以获得更好,更准确的设计帮助,那就太棒了。


IMO为了了解设计模式,最好去现实世界的例子,而不是继续在网上越来越多地阅读它们,然后开始练习。我强烈推荐BalusC(Java和Java EE专家)的这个Q / A:Examples of GoF Design Patterns in Java's core libraries

答案 1 :(得分:0)

为什么这样?

protected AbstractProduct(){
    impl = null;
}

这会在调用result()时导致NullPointerException。

我也看不到AbstractProductProductImpl的观点。只需将代码放在Product

如果只有一个实现,但是如果您打算在将来实施,那么我也会问你为什么需要一个ProductFactory。那就没关系。

答案 2 :(得分: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包依赖于该接口。