Подклассы выпускного класса; или вырожденный декоратор - PullRequest
3 голосов
/ 06 декабря 2009

У меня есть несколько различных представлений одного и того же типа объекта; давайте назовем это вещью. «Вещь» - это маркерный интерфейс. ThingFormat0, ThingFormat1, ThingFormat2 и т. Д. Являются JavaBean-компонентами, которые реализуют Thing. (Поскольку они являются JavaBeans, маршаллер JSON автоматически преобразует их в и из JSON автоматически.) ThingFormat1 имеет всего несколько членов, таких как name и id. ThingFormat2 имеет ссылки URI на другие вещи. В ThingFormat3 есть ThingFormat1 представления этих других вещей и т. Д.

Сериализатор JSON знает, как автоматически преобразовать URI. (Это работает для любого класса, где вы можете использовать toString () и конструктор ClassName (String string) для преобразования.)

Я хочу иметь ThingFormat0, который ведет себя как URI, но реализует интерфейс маркера Thing.

public class ThingFormat0 extends URI implements Thing {}

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

Единственный способ сделать это - создать декоратор (очень вырожденный вид декоратора, так как он не добавляет никакой функциональности в URI). Это легко в некоторых языках типа "утка", но больше боли в Java, потому что я должен обернуть URI и реализовать все методы URI, которые мне нужны. Есть ли более простой способ?

Ответы [ 5 ]

3 голосов
/ 06 декабря 2009

Я могу придумать два простых способа:

  • Если вы используете Eclipse, вы можете иметь методы делегирования для любого поля, сгенерированного автоматически.
  • Скопируйте источник URI в новый класс с именем ThingURI.
2 голосов
/ 06 декабря 2009

Есть ли причина, по которой класс не может использовать композицию вместо наследования?

public class ThingFormat0 implements Thing {
  private final URI uri;

  public ThingFormat0(String uri) { this.uri = URI.create(uri); }

  public ThingFormat0(URI uri) { this.uri = uri; }

  public URI getUri() { return uri; }

  @Override public String toString() {
    return uri.toString();
  }
}
1 голос
/ 06 декабря 2009

Вы не можете создать подкласс финального класса. Период.

В случае URI он почти наверняка является окончательным по соображениям безопасности; то есть, чтобы не дать кому-то нарушить безопасность песочницы, предоставив скрытый подтип URI, который (например) позволяет ему подорвать контроль доступа.

Так что да, вам нужно использовать обертку или декоратор или что-то в этом роде.

0 голосов
/ 06 декабря 2009

Вы находите это трудным, потому что ваши ThingFormat типы не являются URI. Они предоставляют URI и могут соответствовать URI, но это не делает их URI. Возможно, вы жаждете наследования реализации , но наследование интерфейса терпит неудачу здесь, потому что это неправильные отношения is-a ; он терпит неудачу LSP .

Рассмотрим, например, имеет ли ThingFormat схему или фрагментный компонент, или можно ли разрешить ее по некоторому базовому URI. Это аспекты и операции URI, которые не имеют ничего общего с ThingFormat, что бы это ни случилось.

0 голосов
/ 06 декабря 2009
// base class that handles delegation
class BaseThing implements Thing {

   BaseThing(String uri) { ... }

   BaseThing(URI uri) { ... }

   URI getURI() { ... }

   ...
}

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