"类型安全"UUID?

Syl*_*lar 1 java

我们在项目中使用java.util.UUID的大量使用来识别ojbects并对它们进行操作,就像在这个接口中一样:

List<UUID> searchPerson(String text);
Person fetchPerson(UUID personUUID);

List<UUID> searchAdress(String text);
Person fetchAdress(UUID adressUUID);
Run Code Online (Sandbox Code Playgroud)

但是现在发生,是运行时错误的根源,是一个开发者无意中传递一个personUUID到fetchAdress方法,这是不应该的.

有没有办法让这种"类型安全"这样的帽子他不能通过fetchAdress方法传递一个personUUID?也许有一种方法可以使用泛型来做到这一点?

Cor*_*sky 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 { }
Run Code Online (Sandbox Code Playgroud)

如果手动解包以获取UUID对象会让您烦恼,只需在MyUUID上实现完整的UUID API并将每个调用委托给uuid成员.


qno*_*oid 5

好吧,因为你需要的只是一个类型化的 UUID,你可以使用泛型简单地创建一个接口.

package com.stackoverflow.q1747780;

public interface UUIDTyped<T>
{
    public UUID value();
}
Run Code Online (Sandbox Code Playgroud)

现在假设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();
    }
}
Run Code Online (Sandbox Code Playgroud)

概念证明

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,你可以通过虚拟接口逃脱.

概念证明

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());
    }    
}
Run Code Online (Sandbox Code Playgroud)

最后你的服务就像

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);
}
Run Code Online (Sandbox Code Playgroud)

使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

和一个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;
    }

}
Run Code Online (Sandbox Code Playgroud)

测试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");        
    }
}
Run Code Online (Sandbox Code Playgroud)

测试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");        
    }
}
Run Code Online (Sandbox Code Playgroud)