添加受保护的构造函数以允许子类提供不同的实现

时间:2015-10-03 11:43:54

标签: java oop interface

我有以下界面(为简单起见,省略了一些方法):

public interface Container{

    public void put(String s, Object o);
    public Object get(String s);

}

及其实施:

public class ContainerImpl implements Container{

    private Map<Stirng, Object> m;

    public ContainerImpl(){
        m = new HashMap<>();
    }

    //This constructor is used in the case if a client is not satisfied
    //by the HashMap, e.g. in case of Enum it's better to use EnumMap
    protected ContainerImpl(Map<String, Object> m){
        this.m = m;
    }

    public void put(String s, Object o){
        m.put(s, o);
    }
    public Object get(String s){
        m.get(s);
    }
}

我的问题是关于提供这样一个受保护的构造函数是否与incapsulation相反。事实上,我们在内部使用Map向客户提供一些知识。如果dataStructure发生了变化,我们必须从作为参数传递的地图执行转换,这可能会导致一些错误。我想。

3 个答案:

答案 0 :(得分:3)

  

如果提供这样一个受保护的构造函数与封装相反。

你是对的,它确实与ContainerImpl的封装行为相矛盾。

恕我直言,这是一个设计决定; class是否旨在强制执行封装或向客户/调用者公开以支持各种结构。

例如:

只有ContainerImpl

A: default-constructor表示Container的内部存储完全受其concrete-implementation和来电者的约束不能选择不同的存储空间。

<强> B:ContainerImpl

protected ContainerImpl(Map<String, Object> m)

表示调用者可以选择基于Map的存储的性质,即TreeMapHashMapLinkedHashMap或自定义实现。

选择上述方法之一的决定将基于客户的需求和性质。

答案 1 :(得分:2)

您有责任在单个类中创建,使用和封装基础Map。 如果你想跟随SRP,试着留下唯一接受Map作为参数的公共构造函数,使用工厂或后代来封装数据:

protected abstract Map<String, Object> getStorage();

或者,删除所有构造函数并提供:

{{1}}

答案 2 :(得分:1)

我建议使用这样的东西:

protected ContainerImpl(Map<String, Object> m){
    this(); //default constructor, instantiates internal map
    this.m.putAll(m); // copy all values
}

这样你就不会影响封装,但是你会提供一些方便。作为替代方案,您可以提供这样的工厂方法:

protected ContainerImpl create(Map<String, Object> m){
    ContainerImpl impl = new ContainerImpl(); //default constructor, instantiates internal map
    impl.m.putAll(m); // copy all values
    return impl;
}