54

Javaでファクトリパターンを実装しようとしています。CircleとTriangleが拡張するShapeというクラスがあります。問題は、Shapeコンストラクターが2つのパラメーターしか取得しないのに対し、Circleは3つのパラメーターを取得し、Triangleも取得することです(Circleと同じであるため、コードセクションには表示しません)。それをよりよく示すために:

    private interface ShapeFactory{
        public Shape create(int x, int y);
    }

    private class CircleFactory implements ShapeFactory{
        public Shape create(float radius, int x, int y){ //error
            return new Circle(radius, x,y);
        }
    }

この問題を克服する方法はありますか?工場内のユーザーからの入力を受け取ってはなりません(外部から受け取っている必要があります)。

ありがとう!

4

5 に答える 5

34

2つのオプションがあります。

1)抽象ファクトリ

RectangularShape extends Shape

RoundShape extends Shape

そしてRectangularShapeFactoryRoundShapeFactory

2)ビルダー(Effective Javaの項目2も参照)

public Shape {
    private final int x;
    private final int y;
    private final double radius;

    private Shape(Builder builder) {
        x = builder.x;
        y = builder.y;
        radius = builder.radius;
    }

    public static class Builder {
        private final int x;
        private final int y;
        private double radius;

        public Builder(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public Builder radius(double radius) {
            this.radius = radius;
            return this;
        }

        public Shape build() {
            return new Shape(this);
        }    
    }
}

//in client code 

    Shape rectangle = new Shape.Builder(x,y).build();
    Shape circle = new Shape.Builder(x,y).radius(radiusValue).build();
于 2012-12-14T20:59:20.040 に答える
9

あなたがやろうとしていることは、単に不可能です。コンストラクターの引数が異なる場合、クライアントコードはaとCircle同様に異なる作業を行うSquare必要があり、統一されたコードでこれを解決することはできません。ファクトリで発生するはずのコンストラクタ引数の処理以外にファクトリが実行している他の作業がある場合は、これを質問に投稿し、この一般的なコード作業を除外する際の難しさを述べる必要があります。

于 2012-12-14T20:39:06.190 に答える
7

すべての実装は同じ数の引数を取る必要があります。3つのオプションがあります。

  • たとえば、センターを提供するだけでよいように、ファクトリに加算引数を格納してもらいます。
  • 一部の工場がそれらのいくつかを無視するかもしれないとしても、工場にすべての議論をとらせる。
  • 引数は可変長です。たとえば、「double ...」の場合、呼び出し元は、ファクトリの目的を損なうファクトリが何を必要としているかを知る必要があります。私見では。
于 2012-12-14T21:15:34.307 に答える
1

Shapeインターフェイスを使用することは、非常に制限されているため、通常は不適切な設計です。さまざまな形を説明するには、さまざまな情報が必要です。サイズ変更はこの良い例です。円の場合は半径を変更する必要があり、長方形の場合は両側を変更する必要があります。つまり、1つではなく2つのパラメータを渡す必要があります。

これは、実際の形状が収まる必要のある長方形など、ある種の形状記述子を渡すことで解決できます。したがって、すべての形状がクラスで事前定義されており、すべてをスケーリングすることを前提として、適切にサイズ変更できます。カスタムシェイプが必要な場合は、シェイプ記述子を何らかの方法で拡張して、カスタムシェイプに必要なすべての情報を含める必要がありますが、既存のシェイプとの互換性は維持されます。これは必ずしも難しいことではありません。nullになる可能性のあるプロパティまたはパラメータを追加できます。ここでは、新しいパラメーターのみを追加します。

private interface ShapeFactory{
    public Shape create(float x, float y, float width, float height);
}

private class CircleFactory implements ShapeFactory{
    public Shape create(float x, float y, float width, float height){
        float radius = Math.min(width, height);
        return new Circle(radius, x, y);
    }
}

あなたが通常このようにファクトリーを使用するという別の考え(多くの場合、あなたが望むものによってはアッパーも良いかもしれません):

private interface ShapeFactory{
    public Shape create(float x, float y, float width, float height, bool isCircle);
}

private class MyShapeFactory implements ShapeFactory{
    public Shape create(float x, float y, float width, float height, bool isCircle){
        if (isCircle)
            return new Circle(Math.min(width, height), x, y);
        else
            return new Rectangle(width, height, x, y);
    }
}

したがって、ファクトリは必ずしもコンストラクタと同じパラメータを持っているとは限りません。多くの人がこの印象を持っています。なぜなら、彼らは工場を自動化し、それらをインスタンス化する方法についての情報なしでクラスリストのみを渡そうとしているからです。自動化されたDIコンテナによってコミットするのと同じ間違いです。

ここで本当に重要なのは、上位レベルのコードがどのようなShape実装を取り戻すかを知りたいかどうかです。ただし、場合によっては、ある種の一般的な記述子を持っているか、リファクタリングすることがあります。たとえば、必ずしもShape.scale(width, height)メソッドがあるとは限りません。メソッドがある場合、コンストラクターと同様にスケーリングが異なるため、円や長方形のサイズを変更することはできません。しかし、もしあなたが望むのがのようなものを呼ぶことだけならShape.draw(canvas)、私はあなたが行ってもいいと思います。

その間、私は同様の答えを持つ同様の質問を見つけました、多分あなたもそれから学ぶことができます:https ://softwareengineering.stackexchange.com/a/389507/65755

于 2020-01-14T03:25:42.217 に答える
0

次のように、クラスを使用してファクトリ引数をラップできます。

public interface ShapeArguments{
}

public class CircleArguments implements ShapeArguments{
 ...

 public CircleArguments(... radius,... x,... y){
    ...
 }
}

private interface ShapeFactory{
        public Shape create(ShapeArguments args);
    }

    private class CircleFactory implements ShapeFactory{
        public Shape create(ShapeArguments args){
            CircleArguments circleArgs = (CircleArguments)args;
            return new Circle(circleArgs.radius, circleArgs.x,circleArgs.y);
        }
    }

形状引数の間に共通の引数がある場合は、継承を使用してより適切に管理できます

于 2021-02-20T21:59:57.487 に答える