You can provide Enum for public API, and convert it to another Enum for private usage.
E.g. use a Map, where key is public Enum instance and value - private Enum instance.
The problem is that you have to convert data each time the API is called. May require change in many places.
How to expose an enum to public API without the implementation?
-
02-10-2022 - |
Question
I have a class which has a property whose type is an Enum. Example:
enum CarType {
TOYOTA("Japan"),
AUDI("Germany"),
BMW("Germany");
public final String country;
private CarType(String country) { this.country = country; }
}
class Car {
private CarType type;
public CarType getType() { return type; }
}
The class Car
is part of a library, and I would like to expose its functionality, so I create an interface which will be part of the public API, and have the class Car
implement it:
interface ICar {
CarType getType();
}
class Car implements ICar {
private CarType type;
@Override public CarType getType() { return type; }
}
The problem with this approach is that this would require the whole CarType
enum to be published. The CarType
enum might contain additional attributes and methods which I do not want to expose / publish (country
in this example).
What can I do if I want to hide the implementation of CarType
but I still want to expose the possible values (the declared enum values) in a way so that the API users can reference them in switch
and if
statements like this:
ICar car = ...; // Get an instance somehow.
if (car.getType() == CarType.TOYOTA) System.out.println("It's Toyota.");
Making the additional attributes and methods protected
or private
is not a good solution because then other parts of the library would also not be able to reference to them.
Are there any good alternatives to this problem if I want to keep using Enums?
La solution 2
Autres conseils
Although a late one wanted to add my thoughts -
enums can also implement an interface where you can expose only the require details:
public enum CarType implements ICarType {
...
public String getTypeName(){
return name();
}
}
public interface ICarType {
public String getTypeName();
}
So that you plan to use it in if()/switch
ICarType carType; //Not referencing the enum
if("TOYOTA".equalsIgnoreCase(carType.getTypeName())){
print("Toyota....");
}
protected
, private
and package-private
are the main tools you are provided with for this. If you think about your class hierarchy enough you can probably do something using them.
You should consider composition. Have a TypeDetails
class, and have each member of the CarType
contain a TypeDetails
member. You can then restrict access to the TypeDetails
getter to only those people who are supposed to access it while having the TypeDetails
itself visible to all the parts of your library.
If it is strictly necessary to hide the country
attribute to user code, you can go for standard visibility (attributes declared without public
, protected
or private
qualifier, those attributes would only be visible for classes in the same package). I hope this to be useful, but I am aware that is only a patch.
Anyway I cannot fully understand your design and necessities, so probably you have no other option, but maybe what you need is a redesign with encapsulation in mind if you want to protect your code from API misuse