1

Colorこのような基本クラスがあります。このクラスは不変になるように設計されているため、結果にはfinal修飾子があり、setter はありません。

public class Color
{
    public static Color BLACK   = new Color(0, 0, 0);
    public static Color RED = new Color(255, 0, 0);
    //...
    public static Color WHITE   = new Color(255, 255, 255);

    protected final int _r;
    protected final int _g;
    protected final int _b;

    public Color(int r, int b, int g)
    {
        _r = normalize(r);
        _g = normalize(g);
        _b = normalize(b);
    }

    protected Color()
    {

    }

    protected int normalize(int val)
    {
        return val & 0xFF;
    }
    // getters not shown for simplicity
}

このクラスから派生したクラスは、クラスのゲッターColorHSLを提供することに加えて、色相、彩度、明度で構築されます。Colorこれは、物事が機能しなくなる場所です。

のコンストラクターは、いくつかの計算を行ってから、 、、およびColorHSLの値を設定する必要があります。ただし、スーパー コンストラクターは、計算を行う前に呼び出す必要があります。そのため、パラメーターなしのコンストラクターが導入され、最後の 、、およびを後で設定できるようになりました。ただし、パラメーターなしのコンストラクターも設定も (初めて、 のコンストラクター内で) Java コンパイラーによって受け入れられません。_r_b_gColor()_r_b_gColorHSL

この問題を回避する方法はありますか、または、、およびfinalから修飾子を削除する必要がありますか?_r_b_g


編集:

Color最終的に、RGB データと HSL データの両方を含む基本抽象クラスを使用することにしました。基本クラス:

public abstract class Color
{
    public static Color WHITE   = new ColorRGB(255, 255, 255);
    public static Color BLACK   = new ColorRGB(0, 0, 0);
    public static Color RED = new ColorRGB(255, 0, 0);
    public static Color GREEN   = new ColorRGB(0, 255, 0);
    public static Color BLUE    = new ColorRGB(0, 0, 255);
    public static Color YELLOW  = new ColorRGB(255, 255, 0);
    public static Color MAGENTA = new ColorRGB(255, 0, 255);
    public static Color CYAN    = new ColorRGB(0, 255, 255);

    public static final class RGBHelper
    {
        private final int   _r;
        private final int   _g;
        private final int   _b;

        public RGBHelper(int r, int g, int b)
        {
            _r = r & 0xFF;
            _g = g & 0xFF;
            _b = b & 0xFF;
        }

        public int getR()
        {
            return _r;
        }

        public int getG()
        {
            return _g;
        }

        public int getB()
        {
            return _b;
        }
    }

    public final static class HSLHelper
    {
        private final double    _hue;
        private final double    _sat;
        private final double    _lum;

        public HSLHelper(double hue, double sat, double lum)
        {
            //Calculations unimportant to the question - initialises the class
        }

        public double getHue()
        {
            return _hue;
        }

        public double getSat()
        {
            return _sat;
        }

        public double getLum()
        {
            return _lum;
        }
    }

    protected HSLHelper HSLValues   = null;
    protected RGBHelper RGBValues   = null;

    protected static HSLHelper RGBToHSL(RGBHelper rgb)
    {
        //Calculations unimportant to the question
        return new HSLHelper(hue, sat, lum);
    }

    protected static RGBHelper HSLToRGB(HSLHelper hsl)
    {
        //Calculations unimportant to the question
        return new RGBHelper(r,g,b)
    }

    public HSLHelper getHSL()
    {
        if(HSLValues == null)
        {
            HSLValues = RGBToHSL(RGBValues);
        }
        return HSLValues;
    }

    public RGBHelper getRGB()
    {
        if(RGBValues == null)
        {
            RGBValues = HSLToRGB(HSLValues);
        }
        return RGBValues;
    }
}

とのクラスはRGBColorからHSLColor派生し、とのメンバーColorを初期化する単純なコンストラクターを実装します。(はい、基本クラスに派生クラスの静的インスタンスが含まれている場合)RGBValuesHSLValues

public class ColorRGB extends Color
{
    public ColorRGB(int r, int g, int b)
    {
        RGBValues = new RGBHelper(r,g,b);
    }
}

public class ColorHSL extends Color
{
    public ColorHSL(double hue, double sat, double lum)
    {
        HSLValues = new HSLHelper(hue,sat,lum);
    }
}
4

5 に答える 5

8

宣言型のコンストラクターが完了するまでに、最終的な変数を割り当てる必要があります。したがって、サブクラスでスーパーの final フィールドを割り当てることはできません。

ただし、サブクラスの静的ファクトリ メソッドで変換を行うことはできます。

class HSLColor {
    private HSLColor(int r, int g, int b) { super(r,g,b);}

    static HSLColor create(int h, int s, int l) {
        // conversion code here
        return new HSLColor(r,g,b);
    }
}
于 2009-11-14T14:35:32.217 に答える
3

私の知る限り、これを行う唯一の方法は、r、g、および b を計算する関数を使用してスーパー コンストラクターの呼び出しをネストすることです。

super(calculateRGB(...))

そのため、RGB 値を配列として受け取るコンストラクターを Color に追加することを検討してください。

于 2009-11-14T14:37:16.990 に答える
2

はい、方法はわかりますsuper(calculateRGB(...))が、ここでは継承から実質的に何も得られないように見えます。共通のインターフェースを使用するだけです。RGB と HSV は、交換可能な 2 つの異なるカラー モデルにすぎませんか?

Java の問題の背後には、オブジェクト指向分析の問題があると思います。なぜ継承を使用するのですか?

Color を交換可能に操作するだけでよい場合、継承のメリットがまったくないことに気付くかもしれません(また、HSV をスーパークラスの RGB にマッピングするオーバーヘッドが発生するだけです)。 RGB から継承するのではなく、Color インターフェイスを使用することを検討してください。

Color オブジェクトを実際に何に使用するかを確認しないと、より良い設計を提案することは困難です。現時点では、継承のコスト (スーパー コンストラクターの呼び出しでのカラー モデルの変換) が、再利用の唯一の利点を上回っているように見えますnormalize

于 2009-11-14T14:39:52.177 に答える
1

Java では抽象コンストラクターを使用できないため、すべての計算を super の呼び出しに入れることができない限り、現在の設計でやりたいことを行うことはできません。宣言コンストラクターが完了しました。

別の方法は、引数を取り、コンストラクタの外部で計算を行い、最初の引数として super() を呼び出すことができる Color オブジェクト (ファクトリ パターン) を作成するためのいくつかのメソッドを除外することです。

例- Color クラスに次のものがある場合

public Color static createHSLColor(int h, int s, int v) {
   // All the calculation here

   return new ColorHSL(h,s,v);
}

次に、コンストラクターを公開しない (おそらく保護する) ことができます。その後、オブジェクトを作成できる唯一の方法は、ファクトリ メソッドを使用することです。

于 2009-11-14T14:38:22.260 に答える
1

できることの 1 つは、電卓を表すコンストラクター パラメーターを使用することです。たとえば、次のようになります。

public Color(int r, int g, int b, Calc calc) {
   _r = calc.normalize(r);
   _g = calc.normalize(g);
   _b = calc.normalize(b);
}

これにより、サブクラスの必要性が完全になくなる可能性があります。コンストラクターを宣言できます。

public Color(int r, int g, int b) { 
  this(r,g,b, defaultCalc);
}

または、静的なスタイル コンストラクターを提供することもできます。

public static Color hslColor(int r, int g, int b) {
    return new Color(r,g,b, hslCalc);
}
于 2009-11-14T14:38:31.900 に答える