2010-09-01 3 views
4

У меня есть две иерархии классов Java, которые совместно используют общий предок и реализуют общий интерфейс. Мне нужно передать указатель на одну из этих вещей методу в другом классе.Требование аргумента расширяет определенный класс И реализует конкретный интерфейс

interface I { ... } 

class A extends java.awt.Component implements I { ... } 
class B extends java.awt.Component implements I { ... } 

class D { 
    Component c; 
    I i; 
    void m(? x) { 
    c = (Component) x; 
    i = (I) x; 
    } 
} 

Есть ли что-то я могу заменить «?» с, которая позволит мне пройти в либо «A» или «B»? Если я произнес «x» до java.awt.Component и сохранил его в «c» и до I и сохранил его в «i», я теряю выгоду от сильной типизации.

Нужно ли мне объявить

class D { 
    void m(java.awt.Component c, I i) { ... } 
} 

и называем его 'm(a, a)' или 'm(b, b)', где

A a = new A(); 
B b = new B(); 

Я не могу создать

abstract class C extends java.awt.Component implements I {...} 

и передать в потому что ни A, ни B не является C.

Кстати, это можно сделать в Scala?

EDIT: Реальная проблема, которую я пытаюсь решить, что у меня есть два класса, один, который простирается JInternalFrame, а другой, который проходит JPanel. Оба являются абстрактными и предоставляют некоторые общие функции для виджетов, отображаемых в них (JTables, где пользователь может редактировать строки, удалять строки и т. Д.). Код для редактирования и удаления строк всегда один и тот же, независимо от отображения отображаемых типов объектов. У меня есть несколько методов, которые позволяют пользователю щелкнуть строку, выбрать «Удалить» из всплывающего меню и, например, запросить подтверждение, удаляет выбранную строку и объект базы данных. Иногда мне нужен подкомпонент кадра, а иногда и подкомпонент панели. Я создал класс делегата для общей функциональности и переменной экземпляра в каждом из абстрактных классов этого типа делегата. Производные классы JInternalFrame и JPanel просто переносят фактические реализации делегата. Класс делегата, в свою очередь, нуждается в указателе на класс «владелец» для обратных вызовов, чтобы получить выбранную строку таблицы и т. Д., И указатель на характер «Component» каждого родителя для диалоговых окон подтверждения JOptionPane.

Использование подхода generics Java работает очень хорошо. Класс делегата теперь определяется как общий класс на <T extends Component & DelegateContainer, и каждый из классов абстрактных классов реализует DelegateContainer (где объявляются методы обратного вызова).

Если бы я переписал это в Scala, я бы, вероятно, сделал что-то с чертами вместо создания класса делегата. Черты могут «добавить» функциональность удаления к конкретному классу JInternalFrame, например.

Спасибо за быстрые ответы.

+1

A и B являются Компонентами, которые реализуют I ... это требует AbstractIComponent ... почему это не работает для вас? – Arne

+0

@Arne: Я не верю, что это сработает, потому что классы 'A' и' B' не относятся к типу 'AbstractIComponent'. – Ralph

ответ

14

Дженерики на помощь!

public class Test { 
    public static void main(String... args){ 
     new D().m(new A()); 
     new D().m(new B()); 
    } 
} 

interface I { } 

class A extends java.awt.Component implements I {} 
class B extends java.awt.Component implements I {} 

class D { 
    Component c; 
    I i; 
    <T extends java.awt.Component & I> void m(T x) { 
    c = x; 
    i = x; 
    } 
} 

Это не лучший способ сделать что-то, но в вашем случае это работает. Вы должны разделить свой метод на два, один для поведения I, а другой - для поведения Component.

+0

См. ** EDIT ** выше для выяснения проблемы. BTW, решение generics работало очень хорошо. Благодарю. – Ralph

4

В этом случае, если вы хотите сделать, как вы описываете, это, вероятно, имеет смысл создать класс C, который реализует общую функциональность между A и B из которых оба A и B могут продлить.Таким образом, вы можете просто передать класс C в качестве аргумента метода D.m.

Не зная точных классов, трудно сделать этот вызов окончательно. Я просто основываю его на функции, которую вы пытаетесь создать. Поскольку метод D.m, по-видимому, должен быть способен работать на любом из них, должно быть что-то общее.

+0

Это не сработает в моем случае. Классы 'A' и' B' фактически расширяют другие классы, которые расширяют 'Компонент'. Я на самом деле пытаюсь создать новый класс 'D', который действует как делегат, чтобы делать обычные вещи, которые пытаются выполнить A и B. Мне нужно передать 'A' и' B' в конструктор 'D', чтобы он мог перезванивать' A' и 'B'. – Ralph

+0

Это довольно запутанно. Мой инстинкт говорит о том, что необходимо упростить всю схему. Трудно сказать, без подробностей. –

11

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

interface Foo {} 

class Bar {} 

class Impl extends Bar implements Foo {} 

class D { 

    private Foo foo; 
    private Bar bar; 

    <T extends Bar & Foo> void m(T t) { 
     foo = t; 
    } 
} 

public class Test { 
    public static void main(String[] args) { 
     Impl impl = new Impl(); 
     D d = new D(); 
     d.m(impl); 
    } 
} 

Я не знаю, как это поместится в Скала, боюсь.


[Редактируйте Rahul G]

Scala способ тот же. Просто синтаксис отличается.

trait Foo 
class Bar 
class Impl extends Bar with Foo 

class D { 
    private var foo: Foo = _ 
    private var bar: Bar = _ 

    def m[A <: Bar with Foo](a: A) { 
    foo = a 
    bar = a 
    } 
} 

object Main { 
    def main(args: Array[String]) { 
    val impl = new Impl 
    val d = new D 
    d.m(impl) 
    } 
} 
+1

+1. Кстати, добавил мой комментарий к вашему ответу. Блок комментариев не подходит для размещения кодов. – missingfaktor

+2

Я не знал, что вы можете редактировать записи Jon Skeet. Думали, что они будут неизменными или что-то в этом роде ... :-) –

+0

@Missing Faktor: Мне очень нравится. –

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