Требование аргумента расширяет определенный класс И реализует определенный интерфейс - PullRequest
4 голосов
/ 01 сентября 2010

У меня есть две иерархии классов 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;
  }
}

Есть ли что-то, что я могу заменить '?' на то, что позволит мне передать либо ''1005 * 'или' 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?

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

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

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

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

Ответы [ 3 ]

14 голосов
/ 01 сентября 2010

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

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.

11 голосов
/ 01 сентября 2010

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

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);
    }
}

Я не знаю, как это вписывается в Scala, я боюсь.


[Редактировать Рахул G ]

Путь Скала такой же.Просто синтаксис другой.

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)
  }
}
4 голосов
/ 01 сентября 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...