2009-04-01 3 views
1

Для определенного макета, над которым я работаю, мне нужно сделать свой собственный LayoutManager.Как я могу реализовать свой LayoutManager без instanceOf?

Он будет выставлять различные компоненты в зависимости от того, какой тип они являются: Label s в одном направлении, разделители по-другому, и все остальное третьим способом.

Я могу легко это реализовать и определить различные позиции для различных типов компонентов, если сделать метод:

private Dimension calculatePositionForComponent(Component component) { 
    if (component instanceOf JLabel) 
    ... 
    if (component instanceOf JSeparator) 
    ... 
} 

Есть ли лучший способ сделать это без использования instanceOf?

(И нет, я не имею сделать свой LayoutManager, но это делает вещи чрезвычайно легче, если я делать;))

заранее спасибо

/B

ответ

0

только другим практическим способом является использование полиморфизма и функция функции calculatePositionForComponent() для компонента/абстрактного класса компонента. Это может, в свою очередь, использовать данные из фактического менеджера компоновки, а затем возвращать размеры. Неправильно использовать этот подход в вашем конкретном случае в зависимости от того, какие данные должны быть доступны методом calculatePositionForComponent().

Совет при работе с несколькими экземплярами instanceof if должен использовать стиль if-else if-else if-else типа стилизации. Затем в соответствии с практичностью переместите наиболее очевидный выбор в иерархии сравнения, чтобы ускорить if-блок.

0

Похоже, что instanceOf может быть самым простым способом сделать это. Вы не можете использовать перегрузку метода, так как перегрузка метода определяется во время компиляции. Это означает, что вы не можете просто сделать следующие методы:

private Dimension calculatePositionForComponent(JLabel component) { 
    .... 
} 
private Dimension calculatePositionForComponent(JSeparator component) { 
    .... 
} 
.... 

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

Да, используя instanceOf, как правило, это запах кода, и может быть больше способов ООП. Однако для этого конкретного типа кода я видел, что многие продвинутые разработчики используют instanceOf. Это в langauge по какой-то причине, а не только как костыль. Бывают моменты, когда это лучший инструмент для работы. ИМХО, это один из тех времен.

1

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

public interface PositionCalculator { 
    Dimension calculatePositionForComponent(MyLayoutManager manager, Component component); 
} 

class JLabelCalculator implements PositionCalculator { 
    public Dimension calculatePositionForComponent(MyLayoutManager manager, Component component) { 
    // ... 
    } 
} 

class JRadioButtonPosCalculator impements PositionCalculator { 
    public Dimension calculatePositionForComponent(MyLayoutManager manager, Component component) { 
    // ... 
    } 
} 

// More classes ... 


class MyLayoutManager extends LayoutManager { 
    private static HashMap<Class, PositionCalculator> calculators = new HashMap<Class, PositionCalculator>(); 
    public static registerPositionCalculator(Class c, PositionCalculator p) { 
    calculators.put(c, p); 
    } 
    private static PositionCalculator defaultCalculator = new DefaultPositionCalculator(); // Not shown here ... 
    // ... 
    private Dimension calculatePositionForComponent(Component c) { 
    PositionCalculator calc = calculators.get(c.getClass()); 
    if (calc == null) 
     calc = defaultCalculator; 
    return calc.calculatePositionForComponent(this, c); 
    } 
} 

Теперь вы можете зарегистрировать отдельные PositionCalculators для всех компонентов, поставив

MyLayoutManager.registerPositionCalculator(JLabel.class, new JLabelCalculator()); 
MyLayoutManager.registerPositionCalculator(JRadioButton.class, new JRadioButtonCalculator()); 
// ... 

конечно, это решение может страдать от следующих недостатков:

  • это, вероятно, медленнее, чем оригинал.
  • Это не работает с унаследованными классами: если у вас есть подкласс JLabel, вы должны зарегистрировать его отдельно. Решение может быть адаптирована к этому, но это было бы за счет другой потери производительности ...

С другой стороны, решение довольно хорошо расширяемым: Вы можете определить различное поведение макета, не прикасаясь к MyLayoutManager класс.

+0

О, о, это так плохо? : - | – MartinStettner

+0

Я бы очень благодарен короткому намеку на причину затухания ... – MartinStettner

+0

Да, мне нравится знать, почему это было также опущено, потому что это выглядит неплохим способом сделать это (за исключением, возможно, для паритета производительности?) – Brimstedt

1

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

Мои предпочтения касаются интерфейсов менеджера компоновки для добавления компонентов в контейнер, а не по умолчанию, когда контейнер добавляет компоненты в менеджер компоновки. Это позволяет вам построить объект ограничений более естественным образом. В вашем случае вы можете иметь отдельные методы для добавления JLabel, JSeparator и т. Д., Чтобы вам не пришлось повторять эту информацию и иметь разные аргументы.

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