Добавление функций в библиотеки классов Java - PullRequest
6 голосов
/ 04 мая 2010

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

Позволяет назвать недостаточный базовый класс 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, а не B, и вы не можете понижать рейтинг.

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

Ответы [ 4 ]

2 голосов
/ 04 мая 2010

Почему бы не использовать Composition вместо Inheritance?

class ABetterA {
    private A a;

    public ABetterA() {

    }

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

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

2 голосов
/ 04 мая 2010

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

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

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

1 голос
/ 04 мая 2010

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

0 голосов
/ 04 мая 2010

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

Несмотря на то, что AOP обычно используется для изменения существующих методов (до, после или вокруг "advices" = фрагментов кода), вы также можете вводить новые члены и методы - проверьте Объявления типов AspectJ .

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

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