2009-12-06 6 views
2

У меня есть несколько различных представлений одного и того же объекта; назовем это Вещей. «Вещь» - это интерфейс маркера. ThingFormat0, ThingFormat1, ThingFormat2 и т. Д. - все JavaBeans, которые реализуют Thing. (Поскольку они являются JavaBeans, маршаллер JSON автоматически преобразует их в JSON и из него автоматически.) ThingFormat1 имеет всего несколько членов, таких как имя и идентификатор. 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, которые мне нужны. Есть ли более простой способ?

ответ

3

Два простых способов, которыми я могу думать:

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

Вы не можете подклассифицировать окончательный класс. Период.

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

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

2

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

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(); 
    } 
} 
+0

Когда Thing является членом класса Response, сериализация ответа JSON является {"thing": {"uri": "http: // whatever"}} вместо {"thing": "http: // без разницы"}. –

0
// base class that handles delegation 
class BaseThing implements Thing { 

    BaseThing(String uri) { ... } 

    BaseThing(URI uri) { ... } 

    URI getURI() { ... } 

    ... 
} 

class ThingFormat0 extends BaseThing { 
    ... 
} 
0

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

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