Подтвердить что ты не робот

Переопределение метода в экземпляре Java-объекта

Я хотел бы переопределить метод в объекте, который мне передал factory, который у меня малое управление.

Моя конкретная проблема заключается в том, что я хочу переопределить getInputStream и getOutputStream объекта Socket для выполнения проводного журнала.

Общая проблема заключается в следующем:

public class Foo {
    public Bar doBar() {
        // Some activity
    }
}

Где я хочу взять экземпляр Foo и заменить doBar на свой собственный, который будет работать следующим образом:

Bar doBar() {
    // My own activity
    return original.doBar();
}

Для Socket я собираюсь вернуть InputStream и OutputStream, которые завернуты путем ведения журнала для перехвата данных.

4b9b3361

Ответ 1

Так как Java использует OO класса, это невозможно. Что вы можете сделать, это использовать шаблон декоратора, т.е. Написать обертку для объекта, который возвращает обернутые потоки.

Ответ 2

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

Скажите, что у вас есть класс Foo:

public class Foo {
  public Bar doBar() {
    // Some activity
  }
}

Тогда у вас есть класс бегунов или что-то подобное. Вы можете переопределить метод doBar() в момент создания экземпляра, и это затронет только этот конкретный объект.

этот класс может выглядеть следующим образом:

public class FooInstance{
  Foo F1 = new Foo(){
    public Bar doBar(){
      //new activity
    }
  }

  Foo F2 = new Foo();

  F1.doBar(); //does the new activity
  F2.doBar(); //does the original activity found in the class
}

Я не совсем уверен, что сделаю трюк для вас, но, возможно, он поставит вас в правильном направлении. Если ничего другого нельзя переопределить методом вне класса, возможно, это поможет вам.

Ответ 3

Вы не можете заменить методы в существующих объектах - вы не можете изменить существующий тип объекта, с одной стороны.

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

В вашем реальном случае нет способа, которым вы можете просто сделать отдельный вызов для переноса потоков, возвращаемых сокетом? Можете ли вы дать более подробную информацию.

Ответ 4

Использование декоратора - правильный путь:

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

http://www.javaspecialists.eu/archive/Issue058.html

Ответ 5

Я не уверен, что это возможно. Рассматривали ли вы создание своего собственного класса с возвратом объекта factory как членом, а затем с помощью метода doBar() для этого класса.

Ответ 6

Вы не можете реально изменить объект на лету в java.

У вас может быть что-то, что сделает то, что вы хотите, обернув ваш Foo в другой аналогичный объект, который будет делегировать каждый вызов Foo и в том же журнале, что вы хотите. (см. Proxy)

Но если вы хотите вести журнал, возможно, аспект - лучший выбор. (см. AspectJ)

Ответ 7

два варианта:

  • easy: если бы Foo вы реализовали интерфейс, вы можете использовать Динамический прокси, чтобы добавить новые функции.
  • больше работы: у вас есть "советы" AOP - вы можете использовать любой из существующих инструментов АОП, чтобы сделать это возможным. Spring Framework может сделать это за вас, если вы уже используете его.

Ответ 8

Другое связанное с проксированием решение: вы можете использовать Аспекты для переопределения метода на заданном объекте без его подклассификации. Это особенно подходит для регистрации. В этом примере используется spring -aop.

class Example {

    final Foo foo;

    Example(Foo original) {
        AspectJProxyFactory factory = new AspectJProxyFactory();
        factory.setTarget(original);
        factory.addAspect(FooAspect.class);
        foo = (Foo) factory.getProxy();
    }

    @Aspect
    static class FooAspect {

        @Before("execution(Foo.doBar())")
        Object beforeDoBar() {
            // My own activity
        }
    }

Ответ 9

Если Socket был интерфейсом, вы могли бы создать динамический прокси. Ниже приведен пример. Я помещаю это здесь, если другие люди должны это сделать, а целевой экземпляр - это экземпляр интерфейса.

Основная причина, по которой это не будет работать для Socket, заключается в том, что для java.lang.reflect.Proxy.newProxyInstance требуется массив интерфейсов для второго аргумента, поэтому классы здесь не будут работать. В качестве примера для этого примера мне пришлось создать интерфейс под названием ParentInterface, который имеет только три метода печати. ​​

public class Parent implements ParentInterface {

    @Override
    public void print1() {
        System.out.println("parent 1");
    }

    @Override
    public void print2() {
        System.out.println("parent 2");
    }

    @Override
    public void print3() {
        System.out.println("parent 3");
    }

    public static void main(String[] args) {
        Parent originalInstance = new Parent();
        ParentInterface proxied = (ParentInterface) java.lang.reflect.Proxy.newProxyInstance(
                Parent.class.getClassLoader(),
                new Class[]{ParentInterface.class},
                new ParentProxy(originalInstance));

        proxied.print1();
        proxied.print2();
        proxied.print3();

    }

    static class ParentProxy implements InvocationHandler {

        final Object realObject;

        public ParentProxy(Object real) {
            realObject = real;
        }

        @Override
        public Object invoke(Object target, Method m, Object[] args) throws Throwable {
            try {
                if (m.getName().equals("print2")) {
                    print2();
                    return null;
                } else {
                    return m.invoke(realObject, args);
                }
            } catch (java.lang.reflect.InvocationTargetException e) {
                throw e.getTargetException();
            }
        }

        public void print2() {
            System.out.println("wrapper 2");
        }

    }

}