문제

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?

도움이 되었습니까?

해결책 2

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.

다른 팁

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top