- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个值对象 (Test2
),它将包含许多可选的数据结构(PropertySet
的实现)。我不能将它们全部组合到 Test2
中,因为会有很多变体并且实现所有排列会导致类的激增。我提出了以下解决方案:
public class Test2
{
static interface PropertySet
{
}
static class LocationInfo implements PropertySet
{
String lat;
String lng;
public LocationInfo(String lat, String lng)
{
this.lat = lat;
this.lng = lng;
}
}
private Map<Class<? extends PropertySet>, PropertySet> propertySets = new HashMap<>();
@SuppressWarnings("unchecked")
public <T extends PropertySet> T fetchPropertySet(Class<? extends T> propertySetType)
{
T result = (T) propertySets.get(propertySetType);
return result;
}
public LocationInfo getLocationInfo()
{
return this.<LocationInfo> fetchPropertySet(LocationInfo.class);
}
public static void main(String[] args)
{
Test2 test = new Test2();
test.propertySets.put(LocationInfo.class, new LocationInfo("1", "1"));
LocationInfo locationInfo = test.<LocationInfo> fetchPropertySet(LocationInfo.class);
System.out.println(locationInfo.lat + ", " + locationInfo.lng);
LocationInfo locationInfo2 = test.getLocationInfo();
System.out.println(locationInfo2.lat + ", " + locationInfo2.lng);
}
}
我的问题是此解决方案是否被视为解决此类问题的良好做法?
请注意,我不能使用像 Guava 这样的外部库,但使用了 java 8。
最佳答案
如果您的类型有很多可选属性,使用映射就足够了。但是,您使用属性的 type 作为键是有问题的。与普通字段/属性相比,普通字段/属性通过名称区分并且具有类型,即您可以拥有相同类型的多个属性。你的例子 LocationInfo
表明。它表示没有特定含义的位置。完全可以想象,可能有一个实体具有两个 LocationInfo
类型的属性。 ,例如startLocation
和 endLocation
.
因此,您不应混淆使用定义属性的类型和表示值的类型。也就是说,没有理由interface PropertySet
.它不会为类型增加任何值(value),只会增加不必要的约束。
要解决这个问题,请使用同时包含属性名称和类型的键:
public class Test2
{
static class LocationInfo
{
String lat;
String lng;
public LocationInfo(String lat, String lng)
{
this.lat = lat;
this.lng = lng;
}
}
private static final class PropKey {
final Class<?> type;
final String name;
public PropKey(Class<?> type, String name) {
this.type = Objects.requireNonNull(type);
this.name = Objects.requireNonNull(name);
}
@Override
public int hashCode() {
return Objects.hash(name, type);
}
@Override
public boolean equals(Object obj) {
if(obj==this) return true;
if (obj == null || !(obj instanceof PropKey)) return false;
final PropKey other = (PropKey) obj;
return type==other.type && name.equals(other.name);
}
}
private final Map<PropKey, Object> properties = new HashMap<>();
public <T> T fetchProperty(Class<T> type, String name)
{
return type.cast(properties.get(new PropKey(type, name)));
}
// your decision whether this should be public
<T> void putProperty(Class<T> type, String name, T value)
{
Objects.requireNonNull(value);
properties.put(new PropKey(type, name), value);
}
public LocationInfo getPosition()
{
return fetchProperty(LocationInfo.class, "position");
}
public static void main(String[] args)
{
Test2 test = new Test2();
test.putProperty(LocationInfo.class, "position", new LocationInfo("1", "1"));
LocationInfo locationInfo = test.fetchProperty(LocationInfo.class, "position");
System.out.println(locationInfo.lat + ", " + locationInfo.lng);
LocationInfo locationInfo2 = test.getPosition();
System.out.println(locationInfo2.lat + ", " + locationInfo2.lng);
test.putProperty(String.class, "debugInfo", "hello world");
System.out.println(test.fetchProperty(String.class, "debugInfo"));
}
}
如前所述,实体与其属性类型之间不应有紧密联系,因此您可以将 LocationInfo
对于包含纬度/经度对的所有用例,将其分类为顶级类型。强烈建议对此类使用不可变值类型模式,就像您要存储在映射中的所有属性类型一样,因为放置它们的通用方法无法创建防御性副本以防止在多个实例之间错误地共享可变对象的 Test2
.
另一件需要考虑的事情是,由于属性是可选的,getter 方法可能会返回一个 Optional<PropertyType>
。而不是使用 null
编码缺少属性.
关于java - 这是将可选数据结构组合成值对象的最佳方式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31434776/
我正在尝试用 Swift 编写这段 JavaScript 代码:k_combinations 到目前为止,我在 Swift 中有这个: import Foundation import Cocoa e
我是一名优秀的程序员,十分优秀!