Как обернуть класс в java и сохранить интерфейс?
У меня есть класс вроде:
MyClass extends MyAbstractClass implement myInterface1, myInterface2,...
Мне нужно создать новый класс с дополнительными полями:
MyType1 field1;
MyType2 field2;
.......
Кажется, что правильно создать новый класс, который будет включать MyClass, например:
MyWrapClass {
MyClass myClass=new MyClass(...);
MyType1 field1;
MyType2 field2;
.....
Но MyWrapClass используется как тип myInterface1 или myInterface2!
Итак, вопрос: должен ли я объявлять все методы, необходимые для интерфейсов myInterface1, myInterface2 в MyWrapClass? Или существует другой способ?
Спасибо.
Ответы
Ответ 1
В принципе, есть два способа. Первый заключается в расширении базового класса:
public class MySubClass extends MyClass {
private MyType1 field1;
private MyType2 field2;
....
Второй вариант заключается в использовании композиции:
public class MySubClass implements myInterface1, myInterface2 {
private MyClass delegate;
private MyType1 field1;
private MyType2 field2;
// for all methods in myInterface1, myInterface2
public SomeType method1() {
return delegate.method1();
}
...
}
Второй вариант рекомендуется многими Java-гуру:
Книга Джоша Блоха Эффективное Java 2nd Edition
- Пункт 16: Офорт композиции над наследованием
- Пункт 17: Проектирование и
документ для наследования или запретить его
Хороший объектно-ориентированный дизайн - это не либеральное расширение существующих классов. Твой первый инстинкт должен составлять вместо этого.
См. также http://en.wikipedia.org/wiki/Composition_over_inheritance
Состав над наследованием может упростить первоначальный дизайн классов Business Domain и обеспечить более стабильный бизнес-домен в долгосрочной перспективе. Его преимуществом перед наследованием является более тщательная изоляция интересов, чем может быть описана иерархией классов потомков. Кроме того, модели наследования часто придумываются при определении классов бизнес-домена, чтобы понять информацию в проблемной области и не обязательно отражать истинную взаимосвязь различных системных объектов.
P.S.: автогенерирующий код для композиции поддерживается некоторыми из современных IDE
Ответ 2
Не завершайте, просто подкласс:
class MySubClass extends MyClass {
MyType1 field1;
MyType2 field2;
...
Ответ 3
Предполагая, что вы не можете расширить MyClass, тогда нет другого способа, которым вы можете иметь MyWrapClass и использовать его, как MyClass. Например, мне удалось реализовать карту, чтобы обернуть фактическую карту. Он имеет много функций, и каждый из них должен быть реализован, который вы намереваетесь использовать. Здесь немного свободы, в том случае, если вы не планируете передавать ее функции, которую вы не пишете, вы можете добавить все необходимые методы и реализовать только те, которые вам нужны. Хотя чаще всего это не так.
В качестве альтернативы вы можете написать фиктивный класс, который реализует все методы интерфейсов, вызывающих оболочку. Затем вы можете переопределить этот класс своей собственной реализацией, позволяя вам перерабатывать класс-оболочку без необходимости выполнять все методы каждый раз.
Ответ 4
Похоже, что прокси-сервер проблемы может решить:
http://docs.oracle.com/javase/1.5.0/docs/guide/reflection/proxy.html
Будь предупрежден, он медленный (использует отражение)
Ответ 5
Предположим, вы не можете расширить MyClass и хотите использовать MyWrapClass как тип myInterface1 или myInterface2. Вы можете сделать следующее:
MyWrapClass implement myInterface1, myInterface2,...{
MyClass myClass=new MyClass(...);
MyType1 field1;
MyType2 field2;
methodInInterface1 () {
myClass.methodInInterface1 ()
}
....
Вы делегируете реализацию всех методов в myInterface1 и myInterface2 в MyClass.
Я считаю, что это называется композицией.