Как упростить класс без написания и без того простых методов?

У меня есть сложный класс, и я хочу упростить его, реализуя фасадный класс (предположим, что у меня нет контроля над сложным классом). Моя проблема в том, что сложный класс имеет много методов, и я просто упрощу некоторые из них, а остальные останутся такими, какие они есть. Что я подразумеваю под «упрощением», объясняется ниже.

Я хочу найти способ, чтобы, если метод реализован с фасадом, вызвать его, а если нет, то вызвать метод в сложном классе. Причина, по которой я хочу этого, заключается в том, чтобы писать меньше кода :) [меньше значит больше]

Пример:

Facade facade = // initialize
facade.simplified(); // defined in Facade class so call it

// not defined in Facade but exists in the complex class
// so call the one in the complex class
facade.alreadySimple(); 

Варианты, которые приходят на ум, следующие:

Вариант 1. Напишите класс, содержащий переменную сложного класса, и реализуйте сложные, а затем реализуйте простые с прямым делегированием:

class Facade {
    private PowerfulButComplexClass realWorker = // initialize
    public void simplified() {
         // do stuff
    }
    public void alreadySimple() {
         realWorker.alreadySimple();
    }
    // more stuff
}

Но при таком подходе мне нужно будет реализовать все простые методы всего одним оператором делегирования. Поэтому мне нужно написать больше кода (хотя это просто)

Вариант 2. Расширить сложный класс и реализовать упрощенные методы, но тогда будут видны как простые, так и сложные версии этих методов.

В python я могу добиться подобного поведения:

class PowerfulButComplexClass(object):
    def alreadySimple(self):
        # really simple

    # some very complex methods


class Facade(object):
    def __init__(self):
        self.realworker = PowerfulButComplexClass()
    def simplified(self):
        # simplified version of complex methods in PowerfulButComplexClass

    def __getattribute__(self, key):
    """For rest of the PowerfulButComplexClass' methods use them as they are
    because they are simple enough.
    """
        try:
            # return simplified version if we did
            attr = object.__getattribute__(self, key)
        except AttributeError:
            # return PowerfulButComplexClass' version because it is already simple
            attr = object.__getattribute__(self.data, key)
        return attr


obj = Facace()
obj.simplified() # call the one we have defined
obj.alreadySimple( # call the one defined in PowerfulButComplexClass

Так как же это сделать с помощью Java?

Изменить: что я имею в виду под «упрощением»: сложный метод может быть либо методом со слишком большим количеством аргументов

void complex method(arg1, arg2, ..., argn) // n is sufficiently large

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

outArg1 = someMethod(arg1, arg2);
outArg2 = someOtherMethod(outArg1, arg3);
actualResult = someAnotherMethod(outArg2);

поэтому мы хотим иметь что-то вроде этого:

String simplified(arg1, arg2, arg3) {
    outArg1 = someMethod(arg1, arg2);
    outArg2 = someOtherMethod(outArg1, arg3);
    return someAnotherMethod(outArg2);
}

person reader_1000    schedule 08.05.2012    source источник
comment
Что вы подразумеваете под упрощением? Являются ли ваши более простые методы более быстрой специализацией, или их просто легче читать, или что-то еще? Если это оптимизация специализации, то вариант 2 имеет смысл, и ваш простой метод должен проверять, допускают ли аргументы простой случай, и в противном случае вызывать сложный суперкласс по умолчанию. Ваша Java IDE может написать все ваши заглушки за вас.   -  person Julian    schedule 09.05.2012
comment
Я отредактировал вопрос, чтобы уточнить, что я имею в виду под упрощением.   -  person reader_1000    schedule 09.05.2012
comment
Итак, это не класс, который вы хотите упростить, а программа, которую вы планируете написать, используя его. Это имеет больше смысла. Тогда я больше склоняюсь к вашему подходу к инкапсуляции. Это означает, что вы будете реализовывать только тот API, который вам нужен для вашей программы, и вы знаете, когда читаете свой фасад, что никакая дополнительная сложность корневого класса нигде не используется. Это упростит ваши модульные тесты.   -  person Julian    schedule 09.05.2012
comment
Я хочу упростить библиотечный класс. Вот почему я назвал это фасадом. Спасибо за комментарии.   -  person reader_1000    schedule 09.05.2012


Ответы (4)


Это называется Наследование. Рассмотрим следующий код:

class Complex {
    public function complex() { /* Complex Function */ }
    public function simple() { /* Already simple function */ }
}

class SimplifiedComplex extends Complex {
    public function complex() { /* Simplify Here */ }
}

Метод simple() будет работать с объектом SimplifiedComplex.

person Madara's Ghost    schedule 08.05.2012
comment
таким образом, вы все еще можете получить доступ к методу Complex.complex(), явно приведя к нему: ((Complex) simplifiedComplexInstance).complex(). - person yair; 09.05.2012
comment
@yair на самом деле нет. DownCasting по-прежнему вызывает переопределяющий метод. Однако внутри класса вы можете вызвать super.complex() и, возможно, добавить для этого явный публичный метод. Подробнее см. здесь: stackoverflow.com/questions/1032847/ - person Guillaume Polet; 09.05.2012
comment
@GuillaumePolet, вы правильно поняли. Таким образом, это делает решение Истины полным в том, что касается вопроса. - person yair; 09.05.2012
comment
Это вариант 2, о котором я упоминал, но в случае упрощения, такого как уменьшение количества аргументов, будут видны как простой, так и сложный метод, и мы не сможем расширить упрощенный класс другим классом (одиночное наследование) . Но все же это хороший способ добиться этого. - person reader_1000; 09.05.2012

Я думаю, вы уже позвонили. Я бы выбрал вариант 1. Он обеспечивает наибольшую гибкость, учитывая жесткость java.

Я предпочитаю его, потому что он предпочитает композицию наследованию. Хотя это создает больше кода, я считаю, что такие конструкции обычно легче модифицировать в долгосрочной перспективе.

Наследование следует использовать только для моделирования строгих отношений «является а», когда подкласс обязательно обладает всеми свойствами и поведением базового класса. Если вы используете наследование для чего-либо еще, вы напрашиваетесь на неприятности.

Наконец, я не разделяю идею «меньше значит больше» (вставьте здесь невероятно лаконичный, неразборчивый пример на Perl). Я разделяю принцип «Код должен быть настолько простым, насколько это необходимо, и не проще».

person nsfyn55    schedule 08.05.2012
comment
Я думаю, что мы можем посчитать такие вещи, как «Не повторяйся» и возможность повторного использования в рамках «меньше значит больше». На мой взгляд, писать меньше кода — хорошая идея, если это не противоречит удобству сопровождения, удобочитаемости и т. д. - person reader_1000; 10.05.2012

В зависимости от вашего варианта использования вы можете захотеть создать фасад перед некоторыми функциями в сложном классе путем делегирования (вариант 1), и вместо поддержки остальных функций в сложном классе вы предоставляете средства доступа сложный класс напрямую (getComplexClass).

Это может сделать дизайн более понятным. Рассмотрим, например, сложный класс, обрабатывающий большинство функций банковской системы. Создание класса с именем «Учетная запись», который имеет доступ к сложному классу, но использует только методы, относящиеся к банковскому счету, помогает дизайну. Для удобства класс Account может иметь метод getBankSystemForAccount или что-то подобное.

person Buhb    schedule 08.05.2012

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

person Lie Ryan    schedule 09.05.2012