2011-02-08 4 views
2

Hallo,решение Конструкция: расширение интерфейса против нового интерфейса

У меня есть небольшое дизайнерское решение сегодня: Существует существующий интерфейс, называемый «TargetSystem», который только один метод «GetName()». Других распространенных данных об этих целевых системах нет. Теперь у меня есть новый тип целевых систем, которым нужна аутентификация.

Я должен знать, нужна ли целевая система для проверки подлинности или нет (интерфейс должен показать диалог пароля для них). Если ему нужна аутентификация, я должен установить имя пользователя и пароль.

Мое решение: должен ли я расширить существующий интерфейс с помощью методов «needsAuthentication» и «setUsernameAndPassword» или создать новый интерфейс, расширяющий старый, только с помощью метода «setUsernameAndPassword», получив проверку подлинности instanceof.

Важно: Не нужно быть совместимым нисходящим или любой другой причиной, чтобы не касаться старого интерфейса! Я просто обсуждаю с коллегой, что, как правило, является хорошим: создание интерфейсов с такими именами, как «ObjectWithFeatureX», «ObjectWithFeatureY» или создание таких методов, как «hasFeatureX», «hasFeatureY».

ответ

1

В общем, если у вас хороший дизайн, вам не нужен экземпляр.

IMHO: instanecof следует использовать только для классов/интерфейсов, которые вы не можете изменить.

Можете ли вы просто установить имя_пользователяAndPassword() и реализации, которые не нуждаются в нем, просто игнорируют его? Более общий подход будет иметь setUsername() и SetPassword() (однако я предпочитаю все в один метод подход, поскольку он не имеет особого смысла менять только один)

создания интерфейсов с такими именами, как " ObjectWithFeatureX ',' ObjectWithFeatureY 'или создавать такие методы, как' hasFeatureX ',' hasFeatureY '.

Я бы сказал, что нет. ;) Если это возможно абонент не должен иметь код как

if(a instanceof NeedsUsername) { 
    ((NeedsUsername) a).setUsername(username); 
} 

или

if(a.needUsername()) { 
    a.setUsername(username); 
} 

он должен просто

a.setUsername(username); 

EDIT: Вам нужен какой-то слушателю для таких событий, как неудачные пароли. Вы могли бы слушатель как

public interface AuthenticationListener { 
    public void firstUsernamePassword(); 
    public void failedAuthentication(String reason); 
} 
+0

Использование одного или двух методов для имени пользователя и пароля не является точкой, на самом деле я использую setPasswordAuthentication (PasswordAuthentication). Но метод «instanceof» и «needAuthentication» кажется уродливым. Я не мог просто вызвать метод, потому что интерфейс должен знать, показывать ли диалоговое окно пароля или нет - в зависимости от целевой системы. – cornz

+0

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

+0

Я также уже думал о методе проверки правильности входа. Фактически я мог бы использовать вызов этого метода, прежде чем запускать диалог в первый раз - если системе не требуется аутентификация, можно вернуть true без какого-либо имени пользователя и пароля. спасибо – cornz

2

Задайте вопрос себе: AuthenticationSystemесть-TargetSystem?

Раствор без опущенными:

interface TargetSystem{ 
    //Each TargetSystem needs a sort of authentication anyway 
    boolean authentication(AuthenticationContext context); 
    ... 
} 

class NormalTargetSystem implements TargetSystem{ 
    boolean authentication(AuthenticationContext context){ 
     //dummy authentication 
     return true; 
    } 
    ... 
} 
class AuthenticationTargetSystem implements TargetSystem{ 
    boolean authentication(AuthenticationContext context){ 
     //real authentication 
    } 
    ... 
} 
+0

Из корса, но это точно цель моего вопроса. Если AuthenticationSystem расширяет TargetSystem или я должен реализовать методы в каждой целевой системе. @see комментарий следующего ответа – cornz

+0

Я пересмотрел свой ответ. –

+1

Но мне все еще нужно знать, нужна ли TargetSystem аутентификация или нет. Дело в том, что мой интерфейс должен показывать диалоговое окно с паролем для этих систем и не должен показывать диалог для целевых систем, которым не нужна аутентификация. Как эта реализация могла бы ответить на этот вопрос? – cornz

0

, какой путь, как правило, славном один: создание интерфейсов с именами, как 'ObjectWithFeatureX', 'ObjectWithFeatureY' или создавать такие методы, как 'hasFeatureX', 'hasFeatureY'.

Другой вопрос, который вы можете задать себе, - это планы на будущее. Планируете ли вы еще больше возможностей? Если вы видите возможность одного дня с ObjectWithFeatureXAndFeatureY, вы можете рассмотреть образец дизайна Decorator.

Этот пример добавления нескольких функций, таких как полосы прокрутки в окна, показывает хорошее использование шаблона декоратора. http://en.wikipedia.org/wiki/Decorator_pattern#Motivation

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

2

Я не согласен с Питером. Иногда instanceof может даже играть центральную роль в дизайне.

Personnaly, я люблю следующую картину (взрывозащищенный костюм: "на"):

interface Authentifiable { 
    void authentify(...) 
} 

interface Stateful { 
    void saveState(...) 
    void loadState(...) 
} 

interface MyOtherAspect { 
    ... 
} 

А потом, в коде:

void someCode() 
{ 
    for (Server s : servers) 
    { 
    if (s instanceof Authentifiable) 
     ((Authentifiable) s).authentify(...) 
    if (s instanceof Stateful) 
     ((Stateful) s).load(...) 
    ... 
    } 

    for (GridSystem gs : grids) 
    { 
    if (gs instanceof Authentifiable) 
     ((Authentifiable) gs).authentify(...) 
    if (gs instanceof Stateful) 
     ((Stateful) gs).load(...) 
    ... 
    } 
} 

Это позволяет иметь полностью ортогональные «аспекты «работа над любым объектом. У вас может быть объект, реализующий функцию A & B, другие B & C и другие A & C. ... или любую комбинацию любых функций. Если у вас много таких функций, это особенно удобно. Создание одного большого интерфейса для всех из них, где реализация объектов просто обрабатывает все эти функции с пустыми заглушками, может оказаться уродливой.

Кроме того, здесь вы можете проверить, имеет ли конкретный объект определенную функцию, которую вы можете использовать напрямую, например, чтобы разбить список объектов на две группы, один с функцией X, а другой без, чтобы обрабатывать их по-разному.

Части системы, работающие с этими функциями, просто должны проверить, есть ли у объекта свойства A, B или C путем проверки с помощью экземпляра. Это масштабируемое, обратное совместимое и простое.

Это очень конкретный способ обработки вещей и не обязательно подходит для вещей общего назначения. Это особенно подходит, если у вас много ортогональных функций, применяемых к нескольким отдельным объектам.

0

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

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

Так вот один подход мне нравится

public interface Authenticating { 
    void authenticate(String username, String password); 
} 

public interface TargetSystem { 
    String getName(); 

    /** 
    * @return the authentication interface of this object, or 
    * null if authentication is not required. 
    */ 
    Authenticating getAuthenticationInterface(); 
} 

... 

    Authenticating auth = targetSystem.getAuthenticationInterface(); 
    if (auth!=null) { 
    String user = null; 
    String pass = null; 
    // show login dialog and get response 
    auth.authenticate(user, pass); 
    } 

... 

Таким образом, вы можете только вызвать метод AUTHENTICATE, если это необходимо. Возможно, вам придется подумать о лучших именах, хотя :)

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