user6800688
user6800688

Reputation: 155

What is the best practice for extracting these 2 classes to a common class?

I have two very simple classes. Both have 2 variables which are UUIDs, and I'm thinking about what the best approach is for extracting it into a common class.

Below are the classes I have defined:

@AllArgsConstructor
final class ObjectKey
{
    @Getter
    private UUID sourceId;

    @Getter
    private UUID targetId;

    @Override
    public boolean equals(Object o)
    {
        if (this == o)
        {
            return true;
        }
        if (o == null || getClass() != o.getClass())
        {
            return false;
        }

        ObjectKey key = (ObjectKey) o;
        return sourceId.equals(key.getSourceId()) && targetId.equals(key.getTargetId());
    }

    @Override
    public int hashCode()
    {
        return (sourceId.hashCode() + targetId.hashCode()) * 31;
    }
}


final class AnimalKey
{
    @Getter
    private UUID catId;

    @Getter
    private UUID dogId;

    @Override
    public boolean equals(Object o)
    {
        if (this == o)
        {
            return true;
        }
        if (o == null || getClass() != o.getClass())
        {
            return false;
        }

        AnimalKey key = (AnimalKey) o;
        return dogId.equals(key.getDogId()) && catId.equals(key.getCatId());
    }

    @Override
    public int hashCode()
    {
        return (catId.hashCode() + dogId.hashCode()) * 31;
    }
}

So I'm wondering what is the best practice, since both classes basically have the same number of variables with the same type... only that the variable names are different.

Of course one option is to have only 1 class that has generic names like firstID and secondID. But then the code using the getters/setters for these classes are not very easy to read and understand. Is there any obvious approach I'm missing?

Upvotes: 1

Views: 74

Answers (1)

Marc G. Smith
Marc G. Smith

Reputation: 886

I don't think there is anything as elegant as you are envisaging or not much of a necessity/benefit. However, a couple of options that come to mind are to have a common base class and some explicit getters that map to friendlier names and/or and object for a TupleUUID.

@AllArgsConstructor
final class TupleUUID
{
    @Getter
    private UUID primaryId;

    @Getter
    private UUID secondaryId;

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        TupleUUID that = (TupleUUID) o;
        return Objects.equals(primaryId, that.primaryId) 
           && Objects.equals(secondaryId, that.secondaryId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(primaryId, secondaryId);
    }
}
@AllArgsConstructor
class TupleKey {

    @Getter(AccessLevel.PROTECTED)
    private TupleUUID uuid;

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass())  {
            return false;
        }

        TupleKey that = (TupleKey ) o;
        return Objects.equals(key, that.key);
    }

    @Override
    public int hashCode() {
        return uuid.hashCode();
    }
}
@AllArgsConstructor
final class ObjectKey extends TupleKey {
    public UUID getSourceId() {
        return getUuid().getPrimaryId();
    }

    public UUID getTargetId() {
        return getUuid().getSecondaryId();
    }
}
@AllArgsConstructor
final class AnimalKey extends TupleKey {
    public UUID getCatId() {
        return getUuid().getPrimaryId();
    }

    public UUID getDogId() {
        return getUuid().getSecondaryId();
    }
}

Of course, you can mix and match this and get rid of the TupleKey base class or roll TupleUUID into TupleKey instead.

The benefits of this are questionable unless you are going to have a lot of objects with two unique identifiers.

Upvotes: 2

Related Questions