我们在项目中大量使用java.util.UUID来识别ojbects并对它们进行操作,就像在这个界面中一样:
List<UUID> searchPerson(String text);
Person fetchPerson(UUID personUUID);
List<UUID> searchAdress(String text);
Person fetchAdress(UUID adressUUID);
但是现在可能发生的并且是运行时错误的来源是开发人员意外地将personUUID传递给fetchAdress方法,这不应该发生。
有没有办法让这种“类型安全”这样的帽子他无法通过fetchAdress方法传递一个personUUID?也许有一种方法可以使用泛型来做到这一点?
答案 0 :(得分:9)
按合成构建一个包含UUID功能的类,然后为每个所需的UUID“类型”子类化它。
如果您不需要/想要在子类上使用完整的UUID API,那么您可能会非常懒惰并将其包装起来。像这样:
public class MyUUID {
private UUID uuid;
public MyUUID() {
uuid = UUID.randomUUID();
}
public UUID getUUID() {
return uuid;
}
}
public class PersonUUID extends MyUUID { }
public class AddressUUID extends MyUUID { }
如果手动展开以获取UUID对象会让您烦恼,只需在MyUUID上实现完整的UUID API并将每个调用委托给uuid成员。
答案 1 :(得分:5)
因为你需要的只是一个类型的 UUID,你可以使用泛型为它简单地创建一个接口。
package com.stackoverflow.q1747780;
public interface UUIDTyped<T>
{
public UUID value();
}
现在假设Person和Address UUID是从不同的源创建的,您可以为每个源创建一个类,实现该接口。
package com.stackoverflow.q1747780;
import java.util.UUID;
public class UUIDFactory
{
public static class PersonUUID implements UUIDTyped<Person>{
/* (non-Javadoc)
* @see com.stackoverflow.q1747780.UUIDTyped#value()
*/
@Override
public UUID value() {
return UUID.randomUUID();
}};
public static class AddressUUID implements UUIDTyped<Address>{
/* (non-Javadoc)
* @see com.stackoverflow.q1747780.UUIDTyped#value()
*/
@Override
public UUID value() {
return UUID.randomUUID();
}};
public <T> UUIDTyped<T> newUUID() {
return new UUIDTyped<T>()
{
/**
* There is no difference on how Person and Address UUIDs are generated
*/
@Override
public UUID value() {
return UUID.randomUUID();
}
};
}
public UUIDTyped<Person> newPersonUUID(){
return new PersonUUID();
}
public UUIDTyped<Address> newAddressUUID(){
return new AddressUUID();
}
}
概念证明
package com.stackoverflow.q1747780;
import junit.framework.Assert;
import org.junit.Test;
public class UUIDFactoryTest
{
@Test
public void testPersonUUID()
{
UUIDFactory uuidFactory = new UUIDFactory();
UUIDTyped<Person> newUUID = uuidFactory.newPersonUUID();
Assert.assertNotNull(newUUID.value());
}
@Test
public void testAddressUUID()
{
UUIDFactory uuidFactory = new UUIDFactory();
UUIDTyped<Address> newUUID = uuidFactory.newAddressUUID();
Assert.assertNotNull(newUUID.value());
}
}
否则你只需使用虚拟接口即可逃脱。
概念证明
package com.stackoverflow.q1747780;
import junit.framework.Assert;
import org.junit.Test;
public class UUIDFactoryTest
{
@Test
public void testNewUUID()
{
UUIDFactory uuidFactory = new UUIDFactory();
UUIDTyped<Person> newUUID = uuidFactory.newUUID();
UUIDTyped<Address> addressUUID = uuidFactory.newUUID();
Assert.assertNotNull(newUUID.value());
Assert.assertNotNull(addressUUID.value());
}
}
最后你的服务就像
package com.stackoverflow.q1747780;
import java.util.List;
public interface Service<T>
{
public List< UUIDTyped<T> > search(String text);
public T fetch( UUIDTyped<T> uuid);
}
使用PersonService类
package com.stackoverflow.q1747780;
import java.util.List;
public class PersonService implements Service<Person>
{
/* (non-Javadoc)
* @see com.stackoverflow.q1747780.Service#fetch(com.stackoverflow.q1747780.UUIDTyped)
*/
@Override
public Person fetch(UUIDTyped<Person> uuid) {
return null;
}
/* (non-Javadoc)
* @see com.stackoverflow.q1747780.Service#search(java.lang.String)
*/
@Override
public List< UUIDTyped<Person> > search(String text) {
return null;
}
}
和一个AddressService类
package com.stackoverflow.q1747780;
import java.util.List;
public class AddressService implements Service<Address>
{
/* (non-Javadoc)
* @see com.stackoverflow.q1747780.Service#fetch(com.stackoverflow.q1747780.UUIDTyped)
*/
@Override
public Address fetch(UUIDTyped<Address> uuid) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.stackoverflow.q1747780.Service#search(java.lang.String)
*/
@Override
public List<UUIDTyped<Address>> search(String text) {
// TODO Auto-generated method stub
return null;
}
}
测试PersonService的正确类型
package com.stackoverflow.q1747780;
import java.util.List;
import org.junit.Test;
public class PersonServiceTest
{
@Test
public void testFetch()
{
UUIDFactory uuidFactory = new UUIDFactory();
PersonService service = new PersonService();
Person person = service.fetch( uuidFactory.newPersonUUID() );
}
@Test
public void testSearch()
{
PersonService service = new PersonService();
List< UUIDTyped<Person> > uuidList = service.search("foo");
}
}
测试AddressService的正确类型
package com.stackoverflow.q1747780;
import java.util.List;
import org.junit.Test;
public class AddressServiceTest
{
@Test
public void testFetch()
{
UUIDFactory uuidFactory = new UUIDFactory();
AddressService service = new AddressService();
Address address = service.fetch( uuidFactory.newAddressUUID() );
}
@Test
public void testSearch()
{
AddressService service = new AddressService();
List< UUIDTyped<Address> > uuidList = service.search("foo");
}
}
答案 2 :(得分:2)
据我所知,没有真正的方法可以使用'类型安全'UUID。要尝试的一件事是创建一个空人对象并设置其UUID值。所以你的签名可能是这样的:
Person fetchAdress(Person personWithOnlyUUIDSet);
获取机制将负责使用数据存储中的正确值填充发送的Person对象。