3
votes
\$\begingroup\$

I have a class called Foo

public class Foo {
    private String optionalProperty;
    private String name;
    private long uniqueId;
    // getters/setters for above properties
}

For some business reason I need to create an Identifier which I can use to 'identify' Foo instances (having some name/uniqueId) in some business flow. I want to create some FooIdentifier class which will be used to identify Foo instances (this FooIdentifier has other business use cases as well and this is one of the use cases).

Since this FooIdentifier will be either based on name or uniqueId we need to distinguish between those two scenarios, optionalProperty is common in both the scenarios.
I'm considering two designs as follows -
Subclassing -

public abstract class FooIdentifier {

        private String optionalProperty;

        public enum Type {
            NAME_BASED, ID_BASED
        }

        protected FooIdentifier(String optionalProperty) {
            this.optionalProperty = optionalProperty;
        }

        public String getOptionalProperty() {
            return optionalProperty;
        }

        public abstract Type getType();

    }

    public class NameBasedIdentifier extends FooIdentifier {
        private String name;

        public NameBasedIdentifier(String optionalProperty, String name) {
            super(optionalProperty);
            this.name = name;
        }

        public NameBasedIdentifier(String name) {
            this(null, name);
        }

        public String getName() {
            return name;
        }

        @Override public Type getType() {
            return Type.NAME_BASED;
        }
    }

    public class IdBasedIdentifier extends FooIdentifier {
        private long uniqueId;

        public IdBasedIdentifier(String optionalProperty, long uniqueId) {
            super(optionalProperty);
            this.uniqueId = uniqueId;
        }

        public IdBasedIdentifier(long uniqueId) {
            this(null, uniqueId);
        }

        public long getUniqueId() {
            return uniqueId;
        }

        @Override public Type getType() {
            return Type.ID_BASED;
        }
    }

Or plain old class -

public class FooIdentifier {

        private String optionalProperty;
        private String name;
        private long uniqueId;

        public enum Type {
            NAME_BASED, ID_BASED
        }

        public FooIdentifier(String optionalProperty, String name) {
            this.optionalProperty = optionalProperty;
            this.name = name; // will have null check
        }

        public FooIdentifier(String optionalProperty, long uniqueId) {
            this.optionalProperty = optionalProperty;
            this.uniqueId = uniqueId; // will have null check
        }

        public FooIdentifier(String name) {
            this(null, name);
        }

        public FooIdentifier(long uniqueId) {
            this(null, uniqueId);
        }

        public String getOptionalProperty() {
            return optionalProperty;
        }

        public Type getType() {
            return name == null ? Type.ID_BASED : Type.NAME_BASED;
        }

        public String getName() {
            return name;
        }

        public long getUniqueId() {
            return uniqueId;
        }    
    }

Which one will be better?

\$\endgroup\$
2
  • \$\begingroup\$ Did you ever decide on an approach for this? \$\endgroup\$
    – dreza
    Commented Sep 14, 2012 at 19:53
  • \$\begingroup\$ yes, I went with One public class and private inner classes for all the special implementations. \$\endgroup\$
    – Premraj
    Commented Sep 14, 2012 at 20:31

2 Answers 2

2
votes
\$\begingroup\$

Assuming you need to retrieve the string or long values (I don't see getters for them in the single class) I prefer the three classes, with the getter methods also in the base class to avoid a cast. Each derived class would unconditionally throw an exception if the inappropriate getter method is called, whereas a single class needs an if statement in both getters. Same goes for if you added a toString() method, equals(long), equals(string) or other methods to the base class - no if statements for "which type of class am I" that are necessary with a single class.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ So basically you're saying I should have three classes but subclasses should not be visible to the clients and all clients will deal with main FooIdentifier class.. right? \$\endgroup\$
    – Premraj
    Commented Aug 15, 2012 at 18:01
  • 1
    \$\begingroup\$ Yes. Ideally there would be some way to use them without ever having to call getType(). Like a toString() method that converted the long to a string if necessary for accessing the data and an equals( FooIdentifer in) method for comparing them. But maybe getType() is unavoidable. \$\endgroup\$
    – Scooter
    Commented Aug 15, 2012 at 20:47
1
vote
\$\begingroup\$

The old class is interesting :
you can have a double identification, with name and long (long is never null but 0L) for the same 'user', so you will be able to know it.
However if a same 'user' may have two entries, two identities it does not matter, and three class is loosely coupled, if those classes engage opposite traitements, why not.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.