Ответ 1
Так как Java использует OO класса, это невозможно. Что вы можете сделать, это использовать шаблон декоратора, т.е. Написать обертку для объекта, который возвращает обернутые потоки.
Я хотел бы переопределить метод в объекте, который мне передал 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, которые завернуты путем ведения журнала для перехвата данных.
Так как Java использует OO класса, это невозможно. Что вы можете сделать, это использовать шаблон декоратора, т.е. Написать обертку для объекта, который возвращает обернутые потоки.
Я думаю, что есть способ добиться желаемого эффекта. Я видел, как он был использован в качелях с кнопками, позволяющими программисту заставить кнопку что-то делать, когда нажимается.
Скажите, что у вас есть класс 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
}
Я не совсем уверен, что сделаю трюк для вас, но, возможно, он поставит вас в правильном направлении. Если ничего другого нельзя переопределить методом вне класса, возможно, это поможет вам.
Вы не можете заменить методы в существующих объектах - вы не можете изменить существующий тип объекта, с одной стороны.
Вы можете создать новый экземпляр другого класса, который делегирован существующему экземпляру, но также имеет ограничения.
В вашем реальном случае нет способа, которым вы можете просто сделать отдельный вызов для переноса потоков, возвращаемых сокетом? Можете ли вы дать более подробную информацию.
Использование декоратора - правильный путь:
Некоторый очень похожий код с требованием, который у вас есть с сокетами, находится здесь:
Я не уверен, что это возможно. Рассматривали ли вы создание своего собственного класса с возвратом объекта factory как членом, а затем с помощью метода doBar() для этого класса.
Вы не можете реально изменить объект на лету в java.
У вас может быть что-то, что сделает то, что вы хотите, обернув ваш Foo
в другой аналогичный объект, который будет делегировать каждый вызов Foo
и в том же журнале, что вы хотите. (см. Proxy
)
Но если вы хотите вести журнал, возможно, аспект - лучший выбор. (см. AspectJ)
два варианта:
Другое связанное с проксированием решение: вы можете использовать Аспекты для переопределения метода на заданном объекте без его подклассификации. Это особенно подходит для регистрации. В этом примере используется 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
}
}
Если 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");
}
}
}