Добавление функций к Библиотекам классов Java

Я использую Библиотеку классов Java, которая является во многих отношениях неполной: существует много классов, которые я чувствую, должны были встроить дополнительные функции членства. Однако я не уверен в лучшей практике добавления этих функций членства.

Позволяет называют недостаточный базовый класс A.

class A
{
    public A(/*long arbitrary arguments*/)
    {
        //...
    }

    public A(/*long even more arbitrary arguments*/)
    {
        //...
    }

    public int func()
    {
        return 1;
    }
}

Идеально, я хотел бы добавить функцию к A. Однако я не могу сделать этого. Мой выбор между:

class B extends A
{
    //Implement ALL of A's constructors here

    public int reallyUsefulFunction()
    {
        return func()+1;
    }
}

и

class AddedFuncs
{
    public static int reallyUsefulFunction(A a)
    {
        return a.func()+1;
    }
}

Путем я вижу его, у них обоих есть преимущества и недостатки. Предпочтительный вариант дает более чистый синтаксис, чем второе, и более логичен, но имеет проблемы: Скажем, у меня есть третий класс, C, в библиотеке классов.

class C
{
    public A func()
    {
        return new A(/*...*/);
    }
}

Поскольку я вижу его, нет никакого простого способа сделать это:

C c;
int useful = c.func().reallyUsefulFunction();

как тип, возвращенный C.func() A, не a B, и Вы не можете удрученный.

Таким образом, что лучший способ добавить функция членства к классу библиотеки только для чтения?

6
задан Eric 4 May 2010 в 06:17
поделиться

4 ответа

Естественная и частая дилемма. Прочтите об альтернативе композиции и наследования . Вторая альтернатива - это, по сути, композиция, если мы думаем, что объект A передается в конструкторе вместо того, чтобы передавать его в каждом методе, то есть мы будем использовать композицию для реализации оболочки или декоратор паттерн.

Проблема для класса C, возвращающего новый экземпляр класса A, не имеет тривиального решения, как вы догадались, до тех пор, пока класс C решает взять на себя ответственность за создание нового экземпляра. Вот почему следует остановиться и подумать, прежде чем вводить «новый» оператор внутри класса, если есть вероятность, что этот класс будет подклассом. В вашем примере было бы неплохо, если бы вы могли указать классу C, какой конкретный класс нужно вернуть ... но как он узнает, как его создать? Что ж, мы могли бы передать ему объект, который знает, как создать экземпляр объекта класса A (или подкласса) ... Я думаю, у вас достаточно мотивации, чтобы прочитать сейчас о Factories и шаблонах проектирования в целом.

Нет однозначного лучшего ответа, но если хотите быстро: я бы сделал оболочку, класс B не расширяет A, но имеет конструктор с параметром A, он делегирует свои методы (кроме собственных) объекту внутри объекта. Когда вам нужно вызвать метод в классе C (я предполагаю, что вы не можете прикоснуться к классу C), вы можете написать: B b = new B (c.func ())

2
ответ дан 17 December 2019 в 04:43
поделиться

Почему бы не использовать композицию вместо наследования?

class ABetterA {
    private A a;

    public ABetterA() {

    }

    // write wrapper methods calling class' A methods and maybe doing something more
}

Таким образом, вы также можете имитировать множественное наследование ...

2
ответ дан 17 December 2019 в 04:43
поделиться

У вас есть третий вариант. Вы можете использовать Scala (язык, совместимый с Java) и его черты , которые являются миксинами под другим именем.

1
ответ дан 17 December 2019 в 04:43
поделиться

Другой вариант, похожий на предложение Брайана - использовать Aspect Oriented Programming (AOP) инструмент, такой как ApectJ, который позволяет "внедрить" дополнительную функциональность в существующие классы, даже бинарные. Вы можете либо предварительно обработать jar библиотеки, чтобы получить новый с расширенными классами ("static weaving"), либо сделать все это во время выполнения, когда классы библиотеки загружены (так называемый "load-time weaving"). Вы можете посмотреть этот пример AspectJ.

Хотя AOP обычно используется для изменения существующих методов (до, после или вокруг "советов" = кусков кода), вы также можете вводить новые члены и методы - проверьте AspectJ's Inter-type declarations.

Конечно, есть вопрос, поддерживается ли AspectJ на вашей ограниченной платформе.

0
ответ дан 17 December 2019 в 04:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: