“类型安全”UUID?

时间:2009-11-17 10:00:44

标签: java

我们在项目中大量使用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?也许有一种方法可以使用泛型来做到这一点?

3 个答案:

答案 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对象。