-1

以下のこのクラスにあるすべての色を「読み取る」には、新しいクラスでどのような種類のプロセスが必要ですか? クラスを使用してコンポーネントに色を設定し、気に入っています。しかし、アプリケーションでパネルを右クリックして、たとえば背景色を変更できるようにする時が来ました。

これらの色を引き続き使用する際に、コードに関して正しい方向に進むにはどうすればよいでしょうか。ColorFactory.java

次のようなクラスに新しいメソッドを追加することを考え始めたところです。

public Map<String, Color> getColorMapValues(){

    return colorMap;
    //
}
4

2 に答える 2

1

この場合、ソースコードを制御できるため、リフレクションを使用するよりも、ニーズに合わせてクラスをリファクタリングすることをお勧めします(これは高価であるだけでなく、セキュリティポリシーによっては禁止されています)。

一般的に使用される手法はHolder patternです。詳細については、Joshua BlochのEffectiveJava(2nd Edition)Item71を参照してください。スレッドセーフで非ブロッキング構造、つまりを使用することで、読み取りの同期を回避することもできますjava.util.concurrent.ConcurrentHashMap

public class ColorFactory {
    private static class ColorFactoryHolder {
        // creates on instantiation of ColorFactoryHolder
        // synchronization is baked into the JVM, but won't be created until
        // the class is used, see JLS 12.4.1
        static final ColorFactory instance = new ColorMap();
    }
    public static ColorFactory getInstance() { return ColorFactoryHolder.instance; }
    // concurrent hash map - all operations are thread safe
    Map<String,Color> colormap = new ConcurrentHashMap<String,Color>();
    private final Object lock = new Object();
    private ColorFactory() {
        colormap.add("blue",new Color(0,0,255));
        // rest of colors here
    }
    public Color getColor(String spec) {
        if(colormap.containsKey(spec)) return colormap.get(spec);
        // don't synchronize externally - Bloch et al, item 70
        synchronized(lock) { 
            // double check idiom - not broken, as map is thread safe
            if(colormap.containsKey(spec)) return colormap.get(spec);
            Color color = parse(spec); // parse method can be extracted from old code
            colormap.put(spec,color);
            return color;
        }
    }
    private static Color parse(String spec) {
        // parse the color spec here
    }    
}

実際、解析操作は(同期と比較して)非常に高速である可能性が高いため、同期を完全になくすことができます。したがって、値を複数回解析することになります。結果は毎回同じになるため、それほど大きな問題ではありません。Blochetal。を参照してください。詳細については、項目69を参照してください。

public class ColorFactory {
    private static class ColorFactoryHolder {
        // same as above, snipped for brevity
    }
    public static ColorFactory getInstance() { return ColorFactoryHolder.instance; }
    // requires ConcurrentMap reference to get putIfAbsent(K,V) method
    ConcurrentMap<String,Color> colormap = new ConcurrentHashMap<String,Color>();
    // private final Object lock = new Object(); - removed
    private ColorFactory() {
        colormap.add("blue",new Color(0,0,255));
        // rest of colors here
    }
    public Color getColor(String spec) {
        Color result = colormap.get(spec);
        if(result == null) {         
            result = parse(spec); // may parse multiple times, but still
                                  // cheaper than synchronization
            colormap.putIfAbsent(spec,result);            
        }
        return result
    }
    private static Color parse(String spec) {
        // parse the color spec here
    }    
}
于 2012-08-03T16:04:59.323 に答える
1

反射によってカラー マップにアクセスできます。IDE が手元にないため、次のコードを保証することはできませんが、これでうまくいくはずです。

private static Map<String, Color> getColorMap() throws Exception {
    Field colorMapField = ColorFactory.class.getDeclaredField("colorMap");
    colorMapField.setAccessible(true);
    return (Map<String, Color>) colorMapField.get(ColorFactory.getInstance());
}

次に、返されたカラーマップをクエリして、名前で色を取得できます。

Map<String, Color> colorMap = getColorMap();
Color yellow = colorMap.get("yellow");

カラーマップを変更したい場合は、上記の方法で取得するだけで、 put() 「好きな色」 (そう、ピンク・フロイドのリファレンスです!) で、次のメソッドを呼び出します。

public void setColorMap(Map<String, Color> colorMap) throws Exception {
    Field colorMapField = ColorFactory.class.getDeclaredField("colorMap");
    colorMapField.setAccessible(true);
    colorMapField.set(ColorFactory.getInstance(), colorMap);
}

これは、クラスの同期ポリシーに関して非常に危険であることに注意してください。ただし、複数のスレッドでスパムしない限り、機能するはずです。

于 2012-08-02T23:01:02.880 に答える