Checkstyle中默认不允许使用受保护的变量,但是在枚举中是什么?

时间:2014-04-19 18:11:22

标签: java oop enums scope checkstyle

我在eclipse中使用Java,我读了thread

我真的很喜欢home's answer,因为我之前从未真正考虑过它。子类应该真正无法访问成员的整个想法。但是,如果有人想要试一试,我会有一个有趣的边缘案例。

假设我有一个界面Buildable和一个枚举CatanPiece

public interface Buildable
{
    HashMap<Resource, Integer> getCost();
    Buildable build( final PlayerHand payment );
}

public enum CatanPiece implements Buildable
{
    ROAD
    {
        @Override
        public HashMap<Resource, Integer> getCost()
        {
            if ( cost.isEmpty() )
            {
                cost.put( BRICK, 1 );
                cost.put( LUMBER, 1 );
            }
            return cost;
        }
    },

    SETTLEMENT
    {
        @Override
        public HashMap<Resource, Integer> getCost()
        {
            if ( cost.isEmpty() )
            {
                cost.put( BRICK, 1 );
                cost.put( LUMBER, 1 );
                cost.put( SHEEP, 1 );
                cost.put( WHEAT, 1 );
            }
            return cost;
        }
    },

    CITY
    {
        @Override
        public HashMap<Resource, Integer> getCost()
        {
            if ( cost.isEmpty() )
            {
                cost.put( WHEAT, 2 );
                cost.put( ORE, 3 );
            }
            return cost;
        }
    };

    protected final HashMap<Resource, Integer> cost;

    private CatanPiece()
    {
        cost = getCost();
    }

    @Override
    public abstract HashMap<Resource, Integer> getCost();

    @Override
    public Buildable build( final PlayerHand payment )
    {
        return ( payment.remove( cost ) ? null : this );
    }
}

所以Checkstyle给了我关于我正在使用的受保护的HashMap的废话,但是对于那些理解它的人来说,你可以看到我没有人滥用这个变量的问题。我实际上将它设为私有并使用受保护的get方法,但该方法的返回值因实例而异。

可能的答案:忽略checkstyle警告,或者可能包含一个抽象的 init()方法来初始化HashMap,然后简单地为所有成员实现 getCost()方法enum。

您怎么看?

1 个答案:

答案 0 :(得分:2)

Checkstyle对Enums的理解有时是不完整的。我猜想VisibilityModifier支票的作者没想到Enums。枚举是一个角落案例,需要一些额外的检查属性。

然而,在您的情况下,意外地,警告仍然是正确的。我相信在任何情况下都不应该在枚举中使用protected字段。如果在Enum常量中需要特定于实例的状态,请通过构造函数或静态初始化初始化它。

尝试以下方法。这应该会带来几个好处:

  • Checkstyle警告消失了,因为Map现在是private
  • CatanPiece枚举常量现在是常量,因为成本映射是不可变的。
  • 延迟初始化没有开销。 CatanPiece枚举常量的用户可以确保成本映射已正确初始化。

唯一的缺点是,无论何时扩展枚举(例如SHIP),开发人员都不能忘记更新buildCostMap()。这样的错误会很快出现。

public enum CatanPiece implements Buildable
{
    ROAD, SETTLEMENT, CITY;

    private static final Map<CatanPiece, Map<Resource, Integer>> allCosts =
            buildCostMap();

    private static Map<CatanPiece, Map<Resource, Integer>> buildCostMap()
    {
        Map<CatanPiece, Map<Resource, Integer>> result =
            new HashMap<CatanPiece, Map<Resource, Integer>>();

        Map<Resource, Integer> cost = new EnumMap<Resource, Integer>(Resource.class);
        cost.put(Resource.WHEAT, 2);
        cost.put(Resource.ORE, 3);
        result.put(CITY, Collections.unmodifiableMap(cost));

        cost = new EnumMap<Resource, Integer>(Resource.class);
        cost.put(Resource.BRICK, 1);
        cost.put(Resource.LUMBER, 1);
        cost.put(Resource.SHEEP, 1);
        cost.put(Resource.WHEAT, 1);
        result.put(SETTLEMENT, Collections.unmodifiableMap(cost));

        cost = new EnumMap<Resource, Integer>(Resource.class);
        cost.put(Resource.BRICK, 1);
        cost.put(Resource.LUMBER, 1);
        result.put(ROAD, Collections.unmodifiableMap(cost));

        return Collections.unmodifiableMap(result);
    }

    @Override
    public Map<Resource, Integer> getCost() {
        return allCosts.get(this);
    }

    @Override
    public Buildable build(final PlayerHand payment) {
        return payment.remove(cost) ? null : this;
    }
}