создать класс-оболочку с дополнительными функциями в java - PullRequest
0 голосов
/ 05 августа 2020

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

Например, допустим, у нас есть класс A как

public class A{
    void method1(){ ... do something ... }
    void method2(){ ... do something ... }
    void method3(){ ... do something ... }
}

Теперь мне нужен другой класс B, который обертывает класс A, чтобы у него были свои собственные методы, а также, если кто-то запрашивает метод класса A, он должен делегировать его классу A.

public class B{
     // if someone asks method1() or method2() or method3() ... it should delegate it to A
     
     // and also it has own methods
     void method4(){ ... do something ... }
     void method5(){ ... do something ... }
}

Я не могу использовать наследование (т.е. B расширяет A), потому что это непросто с моим вариантом использования (где A имеет конкретный конструктор с некоторыми параметрами, которые мы не можем получить ... но мы можем получить объект A

Я не могу просто делегировать каждую функцию в A, используя объект A (потому что в A есть несколько функций)

Есть ли другой способ получить класс B с указанными ограничениями?

Важное примечание: Класс A обрабатывается кем-то другим. Мы не можем изменить ни одну его часть.

Ответы [ 2 ]

0 голосов
/ 10 августа 2020

То, что вы описали, является шаблоном Decorator, созданным GOF. Об этом есть множество источников по Inte rnet. Он похож на шаблон «Прокси» (как в ответе Павла Поливки), но намерение другое. Вам понадобится шаблон «Декоратор»:

Прикрепите дополнительные обязанности к объекту динамически. Декораторы предоставляют гибкую альтернативу созданию подклассов для расширения функциональности. sourcemaking.com

Как вы написали в комментарии

класс A наследуется от единого интерфейса, содержащего несколько методов

Я предполагаю, что A implements AIntf и содержит все нужные вам методы.

public class BDecorator implements AIntf {
    private A delegate;

    private BDecorator(A delegate) {
        this.delegate = delegate;
    }

    void method1(){ delegate.method1(); }
    // ...

    void method4(){ /* something new */ }

В A есть несколько функций, и я не хочу выполнять утомительную работу по написанию каждого метода явно в B.

Java - многословный язык. Однако вам не нужно делать это вручную, каждая достойная IDE обеспечивает автоматическое создание методов делегата. Таким образом, вам потребуется 5 секунд для любого количества методов.

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

Если вы создаете B, вы несете за это ответственность. Вы хотя бы замечаете, если что-то изменилось. И еще раз: вы можете мгновенно воссоздать измененный метод с помощью IDE.

0 голосов
/ 05 августа 2020

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

  1. Вам нужно расширить классы, это можно сделать, добавив конструктор no arg к классу A , мы по-прежнему делегируем все методы, поэтому не беспокойтесь о недоступных параметрах, мы не беспокоимся об отсутствующих данных, нам просто нужны методы

  2. Вам необходимо иметь CGLIB в пути к классам cglib maven , может быть, он у вас уже есть

Чем

A будет выглядеть

public class A {

    private String arg = "test";

    public A() {
        // noop just for extension
    }

    public A(String arg) {
        this.arg = arg;
    }

    public void method1() {
        System.out.println(arg);
    }
}

B будет выглядеть

public class B extends A implements MethodInterceptor {

    private A delegate;

    private B(A delegate) {
        this.delegate = delegate;
    }

    public static B createProxy(A obj) {
        Enhancer e = new Enhancer();
        e.setSuperclass(obj.getClass());
        e.setCallback(new B(obj));
        B proxifiedObj = (B) e.create();
        return proxifiedObj;
    }

    void method2() {
        System.out.println("a");
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Method m = findMethod(this.getClass(), method);
        if (m != null) { return m.invoke(this, objects); }
        Object res = method.invoke(delegate, objects);
        return res;
    }

    private Method findMethod(Class<?> clazz, Method method) throws Throwable {
        try {
            return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

}

Что вы можете сделать

MyInterface b = B.createProxy(new A("delegated"));
b.method1(); // will print delegated

Это не очень хорошее решение и, вероятно, оно вам не нужно. Пожалуйста, подумайте о рефакторинге вашего кода, прежде чем делать это. Это следует использовать только в c очень специфических случаях.

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