我有以下界面(为简单起见,省略了一些方法):
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发生了变化,我们必须从作为参数传递的地图执行转换,这可能会导致一些错误。我想。
答案 0 :(得分:3)
如果提供这样一个受保护的构造函数与封装相反。
你是对的,它确实与ContainerImpl
的封装行为相矛盾。
class
是否旨在强制执行封装或向客户/调用者公开以支持各种结构。
例如:
只有ContainerImpl
的 A: default-constructor
表示Container
的内部存储完全受其concrete-implementation
和来电者的约束不能选择不同的存储空间。
<强> B:强>
并ContainerImpl
与
protected ContainerImpl(Map<String, Object> m)
表示调用者可以选择基于Map
的存储的性质,即TreeMap
,HashMap
,LinkedHashMap
或自定义实现。
选择上述方法之一的决定将基于客户的需求和性质。
答案 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;
}