Должны ли мои классы ограничивать разработчиков от неправильных действий с ними? - PullRequest
5 голосов
/ 29 ноября 2011

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

Скажем, у меня есть класс, который содержит значения, например java.lang.Integer.Его экземпляры агрегируются другими объектами (MappedObjects) (один-ко-многим или многие-ко-многим) и часто используются внутри методов MappedObjects.По соображениям производительности я также отслеживаю эти отношения в TreeMap (guava MultiMap, не имеет значения), чтобы иметь возможность получать быстрые итерации по объектам MappedObject, привязанным к некоторому диапазону целочисленных ключей.Итак, чтобы поддерживать систему в согласованном состоянии, я должен изменить метод MappedObject.bind (Integer integer), чтобы обновить мою Карту следующим образом:

class MappedObject {
    public void bind (Integer integer) {
        MegaMap.getInstance().remove(fInteger, this);
        fInteger = integer;
        MegaMap.getInstance().add(fInteger, this);
    }

    ...

    private Integer fInteger;
}

Я мог бы просто создать абстрактный класс MappedObject с помощью этого финального метода, заставив другиенаследовать от него, но это грубо.Если я определю MappedObject как интерфейс с методом bind () и предоставлю скелетную реализацию - позже другой разработчик может просто забыть включить его в объект и реализовать метод без обновления Map.

Ответы [ 5 ]

4 голосов
/ 29 ноября 2011

Да, вы должны заставить людей делать правильные вещи с вашим кодом. Отличным примером того, как люди могут поступать неправильно , является метод сервлета init (конфигурация ServletConfig) , который ожидал, что вы сохраните конфигурацию сервлета самостоятельно, но, очевидно, многие забыли сохранить конфигурацию и при запуске их сервлетов просто не работает.

При определении API вы всегда должны следовать принципу open-closed , ваш класс должен быть открыт для расширения и закрыт для модификации. Если ваш класс должен работать так, вы должны открывать точки расширения только там, где они имеют смысл, все остальные функции не должны быть доступны для модификации, поскольку это может привести к проблемам с реализацией в будущем.

1 голос
/ 29 ноября 2011

Я бы сказал, что ваши классы должны быть разработаны для максимально простого использования.

Если вы разрешаете разработчику переопределять методы, вам определенно следует документировать контракт как можно лучше. В этом случае разработчик решает переопределить некоторые базовые функции и, следовательно, несет ответственность за обеспечение реализации, соответствующей договору.

В тех случаях, когда вы не хотите, чтобы разработчик переопределял части функциональности - по соображениям безопасности, если нет разумной альтернативы и т. Д. - просто сделайте эту часть окончательной. В вашем случае метод связывания может выглядеть так:

class MappedObject {
public final void bind (Integer integer) {
    MegaMap.getInstance().remove(fInteger);
    internalBind( integer );
    MegaMap.getInstance().add(fInteger);
}

protected void internalBind( Integer integer ) {
 fInteger = integer;
}

...

private Integer fInteger;

}

Здесь вы позволите разработчику переопределить метод internalBind(), но убедитесь, что bind() выполнит сопоставление.

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

1 голос
/ 29 ноября 2011

По крайней мере, вы должны делать действительно все, что предотвращает ошибки, но не требует усилий.

Например: используйте примитивные типы (int) вместо оболочек (Integer), если переменная не можетбыть нулевым.

Так в вашем bind методе.Если вы не намеревались связывать null, тогда используйте int вместо Integer в качестве типа параметра.

1 голос
/ 29 ноября 2011

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

0 голосов
/ 29 ноября 2011

Если вы считаете, что ваши пользователи API глупы, вам следует запретить неправильное использование.В противном случае вы не должны мешать им делать то, что им нужно делать.

Доминирование и правильное именование классов и методов должны указывать, как использовать ваш API.

...