2010-09-27 2 views
15

Я пытаюсь написать java-программу, которая инициализирует определенные макеты на основе того, что пользователь выбирает. То, что я хочу сделать, - попытаться избежать написания кучи if-операторов, чтобы код мог быть масштабируемым для будущего использования, если необходимо добавить дополнительные макеты. Я слышал, что лучший способ реализовать это - использовать полиморфизм, но мое понимание полиморфизма все еще немного нечеткое.Java: используя полиморфизм, чтобы избежать if-statements?

Скажем, я хочу, чтобы реализовать этот случай:

if (user choose layoutA) { initialize layoutA } 
if (user choose layoutB) { initialize layoutB } 
if (user choose layoutC) {initialize layoutC } 

Я думал о создании интерфейса для классов для реализации. Что меня смущает, так это то, как это работает в main(), разве мне не нужно условное выражение if или switch, чтобы выяснить, какой класс необходимо создать?

interface LayoutHandler { 
    public void initializeLayout(); 
} 

class layoutA implements LayoutHandler { 
    public void initialize Layout {initialize layout A} 
} 
class layoutB implements LayoutHandler { 
    public void initialize Layout {initialize layout B} 
} 
class layoutC implements LayoutHandler { 
    public void initialize Layout {initialize layout C} 
} 

Тогда где-то в основном:

public static void main() { 
    getlayoutselectionfromuser() 
    if (user choose layoutA) { LayoutHandler layout = new layoutA(); } 
    if (user choose layoutB) { LayoutHandler layout = new layoutB(); } 
    if (user choose layoutC) { LayoutHandler layout = new layoutC(); } 

} 

не я по-прежнему требует переключения или Условного оператора в основной программе, чтобы выяснить, какой макет пользователь выбрал во время выполнения?

Спасибо!

ответ

17

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

Преимущество полиморфизма возникает, когда в нескольких местах имеется несколько операторов if-else. Полиморфизм инкапсулирует условную логику для вас. См. this question для некоторых других обсуждений по этой теме.

Такого рода рассеянной логики:

void initLayout() { 
    if (user choose layoutA) { initialize layoutA } 
    if (user choose layoutB) { initialize layoutB } 
    if (user choose layoutC) {initialize layoutC } 
} 

void refreshLayout() { 
    if (user choose layoutA) { refresh layoutA } 
    if (user choose layoutB) { refresh layoutB } 
    if (user choose layoutC) { refresh layoutC } 
} 

void cleanupLayout() { 
    if (user choose layoutA) { cleanup layoutA } 
    if (user choose layoutB) { cleanup layoutB } 
    if (user choose layoutC) { cleanup layoutC } 
} 

заменяется чем-то проще:

layout = getLayout(user choice); 

    layout.initLayout(); 
    layout.refreshLayout(); 
    layout.cleanupLayout(); 
+1

Вы можете использовать отражение, чтобы избежать утверждений if вместе. – Dan

2

Короче говоря, да. Вам понадобится ifs или какой-нибудь механизм отображения.

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

Этого можно избежать, но вы в конечном итоге запутываете свой код, и, в конце концов, вероятно, будет что-то вроде if. Вы должны определить отображение из пользовательского ввода в объект; что нельзя обойти. Самый ясный наиболее удобный способ сделать это - это то, что у вас уже есть (хотя я бы добавил иначе ifs. :))

Идея, которую вы имеете для другого класса для каждого макета, неплоха. Это очень похоже на концепцию traits class. Посмотрите на это тоже. Это будет полезно для вашего дизайна.

+0

В этом случае мне было интересно узнать, какие преимущества создают интерфейс, который выступает против использования кучи if-утверждений, подобных мне изначально? Это в первую очередь для удобства чтения? В конце концов, я все еще буду использовать if-statements в качестве контроллера. – user459811

+0

Наличие общего интерфейса для всех ваших макетов означает, что вам не нужно переписывать свой код для каждого нового интерфейса.Основной код по-прежнему будет использовать новый макет так же, как он использовал старые макеты (через один и тот же интерфейс). Это отлично подходит для обслуживания. Что касается ifs, то предложение hvgotcodes карты будет лучше, если вы знаете, что в будущем вы добавите кучу новых макетов. Это не огромная разница (добавьте элемент if, если добавить элемент карты), но он, как правило, более чистый. – JoshD

+0

Вы начнете видеть преимущества Полиморфизма в первый раз, когда вам придется реплицировать эту структуру инструкций if-else во втором месте для другой функции. –

2

№ Использование карты. Когда вы получаете выбор, просто найдите обработчик на карте и отпустите.

psuedocode

Map handlers = new Map() 
handlers.put(layoutA, HandlerForA) 
// more handlers, possibly use dependency injection 

Layout chosen = user choose layout // get a ref to the selected layout 
Handler handler = handlers.get(chosen) 
if (handler == null) { // No HandlerException } 
handler.go() 

только один, если заявление.

+1

Имеет смысл, но мы пока не знаем его варианты использования. Карта может быть или не быть подходящей, несмотря на чистоту решения. –

1

Что-то, где-то, необходимо указать реализацию. Это может быть цепочка операторов if в исходном коде, но это может быть и другое; например, имя класса, указанное во внешнем источнике данных, созданное посредством отражения.

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

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

1

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

Точная реализация зависит от ваших целей, но я бы подумал, что у вас будет один класс, который реализует LayoutHander и имеет ссылку на ссылку на макет. Когда пользователь выбирает свой макет, полиморфизм захватывает ЗДЕСЬ, а не уровень выше, как у вас сейчас. То есть, если объектом, определяющим другое поведение, является «Макет», тогда вам нужно сделать Политику Layout, а не LayoutHander.

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

+0

Моя общая цель - создать класс обертки, который инкапсулирует каждый тип макета. У каждого макета также будет свой собственный набор функций. Например, layoutA способен печатать на HTML, а layoutB способен печатать на XML. По этой причине каждый макет создается по-разному. Я хотел иметь возможность реализовать мой main() таким образом, чтобы он был легко читаемым и поддерживаемым. Кроме того, это позволит добавлять будущие классы макета где-то вниз по линии. – user459811

3

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

LayoutHandler ~> Interface 

LayoutHandlerA, LayoutHandlerB, etc implements LayoutHandler 

Map<String, LayoutHandler> handlers = new HashMap<...>(); 

LayoutHandler handler = handlers.get(userSelectedLayout); 

handler.handle(); 
1

Я думаю, что использование if-statements для инициализации в порядке. Вы пытаетесь избежать повторного использования if-statements для «выбора» поведения во всей программе. Использование if-инструкций для инициализации в порядке.

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

Например, вот некоторые подходы к решению этой проблеме от простого к более сложному:

  • использовать этот инициализатору если-заявление
    • использует жестко закодированные ссылки на реализацию классов непосредственно в логике программы (сложнее найти)
  • инициализировать некоторую структуру данных (например,Карта) с возможными классами, реализующими
    • все еще жестко закодированные ссылки на классы реализации
    • обычно проще добавить классы, реализующие
    • код является немного более сложным и абстрактным, чтобы понять и отлаживать
  • динамическая регистрация
    • нет жестко закодированных ссылок на классы реализации в приложении
    • требуется дополнительная настройка
    • код труднее понять, не зная, как регистрация настройка для работы

Хорошим примером последнего метода (динамической регистрации), чтобы смотреть на то, как работает JDBC. Драйверы JDBC регистрируются в приложении с использованием Class.forName(), а затем с помощью JDBC-URL выбирается конкретный драйвер JDBC. Вот типичный рабочий процесс:

  1. Потенциальные целевые драйверы JDBC добавлены в класс pathpath.

  2. Приложение настроено со списком этих драйверов, например. путем перечисления драйверов JDBC в файле свойств.

  3. Приложение инициализируется путем вызова Class.forName() для каждого водителя в списке. Каждый драйвер знает, что зарегистрировался с помощью DriverManager, когда он загружается Class.forName()

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

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

Это была бы противоположная крайность, чтобы избежать этих if-утверждений.

1

«..для использования в будущем, если больше макетов должны быть добавлены»

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

0

Вы должны использовать фреймворк, чтобы избежать необходимости создавать o определять поведение.

Весна позволяет нам решить эту проблему. Он использует заводскую модель и больше шаблонов проектирования. Таким образом, используя аннотации или файл конфигурации xml, вы можете решить, какие классы создаются. PD: Конечно, я на 100% уверен, что весна использует if's. Но это доказано и используется во многих надежных и надежных приложениях.

Смежные вопросы