1

为了在 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 设计的初学者水平技能,所以我似乎很难发现可能的故障。那么这有什么问题吗?或者它是一些已经实践过的模式?

4

3 回答 3

4

您尝试实现的唯一设计模式是类中的工厂方法ProductFactory。那是唯一想要的设计模式。

由于您当前的代码非常不灵活,因此甚至可以将整体视为反模式,更具体地说:

  • 闹鬼,因为Product只是为了执行而存在ProductImpl#result
  • 调用 super,因为Product只使用super调用。
  • 意外的复杂性,即使过程不仅仅是简单的int乘法。
  • Cargo cult,因为您仍然没有意识到为什么以及何时使用设计模式。

(可能还有更多……)

说明:您的工厂方法模式非常不灵活。请注意,Productclass ispublic但是有一个protected构造函数(甚至标记为一个final类,这很奇怪:为什么要在一个永远不能protected被继承的类上拥有方法?),这意味着它至少应该与.ProductFactoryProduct


正如我在其他评论中直接针对您的问题所指出的那样,如果您解释功能要求以获得更好和更准确的设计帮助,那将会很棒。


IMO为了学习设计模式,最好去现实世界的例子,而不是在网上阅读越来越多的关于它们,然后开始练习。我强烈推荐 BalusC(Java 和 Java EE 专家)的这个问答:Java 核心库中的 GoF 设计模式示例

于 2013-09-27T05:39:42.687 回答
0

为什么要这样做?

protected AbstractProduct(){
    impl = null;
}

这将在调用时导致 NullPointerException result()

我也看不到AbstractProductand的意义ProductImpl。只需将代码放入Product.

如果只有一个实现,我也会质疑为什么你需要一个ProductFactory,但如果你计划在未来实现,那么它就可以了。

于 2013-09-27T04:59:43.010 回答
0

If it were me, I'd break it down like this:

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

With the internal-facing package contents as:

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

You don't need an abstract class, and you definitely don't want Product extending it. You should be using encapsulation here. This protects your Product class from changes to the internal interface - methods can be added without Product getting them unless you choose it.

If you wind up with more implementations and you want an abstract parent, you can choose whether or not each implemention extends it because your external package is relying on the interface.

于 2014-12-05T15:04:53.337 回答