Подтвердить что ты не робот

Каков наилучший способ разделить только методы getter для клиента?

Я пишу API с таким классом:

public class NKMPMission {
    private String name;
    private int age;
    public NKMPMission(String name, int age)
    {
         this.name  = name;
         this.age   = age;
    }
    public String getName() 
    {
       return name;
    }

    public int getAge() 
    {
       return age;
     }
   }

Мои вопросы:

  • Как я могу убедиться, что пользователь этого класса NKMPMission обращается только к получателям?
  • Как я могу представить сеттеры для этой функции, чтобы я как разработчик мог установить, но пользователь не может установить?
4b9b3361

Ответ 1

Обычный способ сделать это - не подвергать класс вообще, просто выставлять интерфейсы для этого класса. Один интерфейс для широкой публики и один для разработчиков.

Затем вам понадобится factory, чтобы создать их.

/**
 * Expose this interface to the public.
 */
public interface INKMPMission {

    public String getName();

    public int getAge();

}

/**
 * Only expose this interface to developers.
 */
interface IDeveloperNKMPMission {

    public void setName(String name);

    public void setAge(int age);

}

public static class NKMPMissionFactory {

    /**
     * Expose only the INKMPMission construction.
     */
    public INKMPMission make(String name, int age) {
        return new NKMPMission(name, age);
    }

    /**
     * Protected version for developers.
     */
    IDeveloperNKMPMission forDeveloper(INKMPMission it) {
        return IDeveloperNKMPMission.class.cast(it);
    }

    /**
     * Private so no-one outside the factory knows about the inner workings.
     */
    private static class NKMPMission implements INKMPMission, IDeveloperNKMPMission {

        private String name;
        private int age;

        private NKMPMission(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public int getAge() {
            return age;
        }

        @Override
        public void setName(String name) {
            this.name = name;
        }

        @Override
        public void setAge(int age) {
            this.age = age;
        }
    }
}

Для действительно параноидального вы можете даже использовать прокси. Это затруднит (но не невозможно) использование сеттеров через отражение.

    /**
     * Expose only the INKMPMission construction.
     */
    public INKMPMission make(String name, int age) {
        return new NKMPMissionProxy(new NKMPMission(name, age));
    }

    /**
     * Protected version for developers.
     */
    protected IDeveloperNKMPMission forDeveloper(INKMPMission it) {
        if (it instanceof NKMPMissionProxy) {
            it = ((NKMPMissionProxy) it).theMission;
        }
        return IDeveloperNKMPMission.class.cast(it);
    }

    /**
     * A proxy for the truly paranoid - makes using reflection more difficult (but not impossible)
     */
    private static class NKMPMissionProxy implements INKMPMission {
        private final NKMPMission theMission;

        private NKMPMissionProxy(NKMPMission theMission) {
            this.theMission = theMission;
        }

        @Override
        public String getName() {
            return theMission.getName();
        }

        @Override
        public int getAge() {
            return theMission.getAge();
        }


    }

Ответ 2

1) Как я могу убедиться, что пользователь этого класса NKMPMIssion получает доступ только к getters.

Вы не можете.

2) Как я могу представить сеттеры для этой функции, чтобы как разработчик я мог установить, но пользователь не должен устанавливать.

Похоже, вы пишете API. Если вы возвращаете экземпляр NKMPMIssion из общедоступного метода этого API, могут быть вызваны сеттеры. Даже если вы отметите их private или protected, их все равно можно вызвать через отражение. Тем не менее, достаточно сделать их не public. По крайней мере, он говорит: "Если вы называете это, вы находитесь в неподдерживаемой территории".

Если вы хотите сделать это сложнее, вы можете вернуть экземпляр, который обертывает фасад вокруг экземпляра NKMPMIssion. Но это просто делает его сложнее, а не невозможно, поскольку экземпляр фасада должен иметь ссылку на экземпляр NKMPMIssion, который (даже если он private) доступен через отражение.

Ответ 3

Самое простое - заставить API использовать только интерфейс и сделать класс детализацией реализации.

public interface INKMPMission {        
    String getName();
    int getAge();
 }

public class SomeService{
    private class MyNKMPMission implements INKMPMission {
        //put getters and setters here
    }
    public List<INKMPMission> getMissions(){
        //put some MyNKMPMissions in a list
    }
}

Так как MyNKMPMission является частным, потребители никогда не смогут сделать снимок и получить доступ к сеттерам.

Ответ 4

Вы можете (каким-то образом), но вы должны не делать это следующим образом:

  • В каждом сеттере создайте новый Exception
  • Осмотрите созданный Stacktrace
  • Если класс вызывающего абонента не входит в ваш пакет (или жесткий код некоторых прямых имен классов/имен методов), запустите IllegalAccessError

Этот способ не является ни красивым, ни быстрым, поскольку вы должны проверять каждый доступ к сеттеру.

Другим способом будет использование @CallerSensitive Annotation, хотя он является защищенным API и поэтому недоступен для всех реализаций plattforms/jre: fooobar.com/questions/202306/...

Чистый, и в большинстве случаев достаточно использовать интерфейс, который предоставляет только клиенту-клиенту и возвращает его клиенту.

Ответ 5

Кажется, вы пытаетесь написать API. Предполагая, что пользовательские средства, разработчики, которые используют ваш API.

В таких случаях сделайте установщик как protected и создайте какую-либо значимую структуру пакета, так что это могут видеть только дочерние элементы и члены пакета.

Если вы хотите защитить это даже от ребенка, нет другого способа сделать его закрытым.

Ответ 6

Отвечая на вопросы:

Q1. Вы не можете как T.J. Кроудер сказал в своем ответе.

Q2. Я бы порекомендовал вам попробовать следующие вещи в следующем порядке от самых простых до самых сложных и воспользоваться тем вариантом, который вы считаете наиболее подходящим с точки зрения усилий-возврата:

Что бы я сделал:

Если ваш набор классов будет использоваться внутри, я бы выбрал вариант 1 в сочетании с хорошими стандартами javadoc и project, этого должно быть достаточно.

Если вы создаете публичный API, я бы воспользовался опцией 2.

IMHO опция 3 добавляет слишком сложную сложность в этом случае, и очень мало пользы, поскольку любой метод или атрибут класса можно получить в любом случае, отражая (как многие люди упомянули). Я думаю, что всем известно о том, что отражение доступа к API скрытым методам является взломанным, опасным и не удобным для совместного использования проектов, поскольку поставщики API имеют право изменять реализации скрытых методов без дополнительного уведомления конечных пользователей.