Jump to content

Пересылка (объектно-ориентированное программирование)

В объектно-ориентированном программировании пересылка означает , что использование члена объекта ( свойства или метода ) приводит к фактическому использованию соответствующего члена другого объекта: использование перенаправляется на другой объект. Пересылка используется в ряде шаблонов проектирования , где некоторые члены перенаправляются другому объекту, а другие обрабатываются напрямую используемым объектом. Объект пересылки часто называют объектом-оболочкой , а явные члены пересылки называются функциями-оболочками .

Делегация

[ редактировать ]

Пересылку часто путают с делегированием ; формально это взаимодополняющие понятия. В обоих случаях имеется два объекта, и первый (отправляющий, оберточный) объект использует второй (получающий, оберточный) объект, например, для вызова метода. Они отличаются тем, что self ссылается на принимающий объект (формально, в среде оценки метода на принимающем объекте): при делегировании он ссылается на отправляющий объект, а при пересылке — на принимающий объект. Обратите внимание, что self часто используется неявно как часть динамической диспетчеризации (разрешение метода: к какой функции относится имя метода).

Разница между пересылкой и делегированием заключается в привязке параметра self в оболочке при вызове через оболочку. При делегировании параметр self привязан к оболочке, при пересылке — к оболочке. ... Переадресация — это форма автоматической повторной отправки сообщений; делегирование — это форма наследования с привязкой родителя (суперкласса) во время выполнения, а не во время компиляции/связывания, как при «обычном» наследовании. [1]

Например, учитывая следующий код:

// Sender
void n() {
  print("n1");
}

// Receiver
void m() {
  print("m2, ");
  n();
}

void n() {
  print("n2");
}

В рамках делегирования, m() выведет м2, н1 потому что n() оценивается в контексте исходного (отправляющего) объекта, а при пересылке выводится м2, н2 потому что n() оценивается в контексте принимающего объекта. [1]

При обычном использовании пересылку часто называют «делегированием» или считают формой делегирования, но при осторожном использовании они четко отличаются по тому, что self относится к. Хотя делегирование аналогично наследованию , допуская повторное использование поведения (и, в частности, повторное использование кода ) без изменения контекста оценки, пересылка аналогична композиции , поскольку выполнение зависит только от принимающего объекта (члена), а не от (исходного) отправляющего объекта. В обоих случаях повторное использование является динамическим, то есть определяется во время выполнения (на основе объекта , которому делегировано или перенаправлено использование), а не статическим, то есть определяется во время компиляции/связывания (на основе класса , от которого унаследовано). Как и наследование, делегирование позволяет отправляющему объекту изменять исходное поведение, но подвержено проблемам, аналогичным хрупкому базовому классу ; при этом пересылка обеспечивает более сильную инкапсуляцию и позволяет избежать этих проблем; см. композицию вместо наследования . [1]

Простой пример явной пересылки в Java: экземпляр B перенаправляет вызовы на foo метод его a поле:

class B {
    A a;
    T foo() { return a.foo(); }
}

Обратите внимание, что при выполнении a.foo(), this объект a (подтип A), а не исходный объект (экземпляр B). Дальше, a не обязательно должен быть примером A: это может быть экземпляр подтипа. Действительно, A даже не обязательно должен быть классом: это может быть интерфейс/ протокол .

В отличие от наследования, при котором foo определяется в суперклассе A (который должен быть классом, а не интерфейсом), а при вызове экземпляра подкласса B, он использует код, определенный в A, но this объект по-прежнему является экземпляром B:

class A {
    T foo() { /* ... */ };
}

class B extends A {
}

В этом примере Python класс B пересылает foo метод и x собственность на объект в его a поле: используя их на b (пример B) то же самое, что использовать их на b.a (пример A которому они пересылаются).

class A:
    def __init__(self, x) -> None:
        self.x = x

    def foo(self):
        print(self.x)

class B:
    def __init__(self, a) -> None:
        self.a = a

    def foo(self):
        self.a.foo()

    @property
    def x(self):
        return self.a.x

    @x.setter
    def x(self, x):
        self.a.x = x

    @x.deleter
    def x(self):
        del self.a.x

a = A(42)
b = B(a)
b.foo()  # Prints '42'.
b.x  # Has value '42'
b.x = 17   # b.a.x now has value 17
del b.x  # Deletes b.a.x.
Диаграмма классов UML, иллюстрирующая пересылку.
UML class diagram that illustrates forwarding.

В этом Java примере Printer в классе есть print метод. Этот метод печати вместо выполнения самой печати перенаправляется объекту класса RealPrinter. Внешнему миру кажется, что Printer объект выполняет печать, но RealPrinter объект — это тот, кто фактически выполняет работу.

Пересылка — это просто передача обязанности кому-то/чему-то другому. Вот простой пример:

class RealPrinter { // the "receiver"
    void print() { 
        System.out.println("Hello world!"); 
    }
}

class Printer { // the "sender"
    RealPrinter p = new RealPrinter(); // create the receiver
    void print() {
        p.print(); // calls the receiver
    }
}
 
public class Main {
    public static void main(String[] arguments) {
        // to the outside world it looks like Printer actually prints.
        Printer printer = new Printer();
        printer.print();
    }
}

Более сложным случаем является шаблон «Декоратор» , который с помощью интерфейсов позволяет сделать пересылку более гибкой и безопасной по типам . «Гибкость» здесь означает, что C не нужно ссылаться на A или B никак, так как переключение переадресации абстрагировано от C. В этом примере класс C может пересылаться в любой класс, реализующий интерфейс I. Сорт C имеет способ переключиться на другой сервер пересылки. В том числе implements Предложения улучшают безопасность типов , поскольку каждый класс должен реализовывать методы в интерфейсе. Главный компромисс — больше кода.

interface I {
	void f();
	void g();
}
 
class A implements I {
	public void f() { System.out.println("A: doing f()"); }
	public void g() { System.out.println("A: doing g()"); }
}
 
class B implements I {
	public void f() { System.out.println("B: doing f()"); }
	public void g() { System.out.println("B: doing g()"); }
}
 
// changing the implementing object in run-time (normally done in compile time)
class C implements I {
	I i = null;
	// forwarding
	public C(I i){ setI(i); }
	public void f() { i.f(); }
	public void g() { i.g(); }
 
	// normal attributes
	public void setI(I i) { this.i = i; }
}
 
public class Main {
	public static void main(String[] arguments) {
		C c = new C(new A());
		c.f();	// output: A: doing f()
		c.g();	// output: A: doing g()
		c.setI(new B());
		c.f();	// output: B: doing f()
		c.g();	// output: B: doing g()
	}
}

Приложения

[ редактировать ]

Переадресация используется во многих шаблонах проектирования. [2] Переадресация используется непосредственно в нескольких шаблонах:

Переадресация может использоваться и в других шаблонах, но часто ее использование модифицируется; например, вызов метода одного объекта приводит к вызову нескольких разных методов для другого:

  1. ^ Jump up to: а б с Бючи, Мартин; Век, Вольфганг (2000). «Общие обертки» (PDF) . ЭКООП 2000 — Объектно-ориентированное программирование . Конспекты лекций по информатике. Том. 1850. С. 212–213 . дои : 10.1007/3-540-45102-1_10 . ISBN  978-3-540-67660-7 .
  2. ^ Гамма, Эрих ; Хельм, Ричард ; Джонсон, Ральф ; Влиссидес, Джон (1995). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Аддисон-Уэсли . Бибкод : 1995dper.book.....G . ISBN  978-0-201-63361-0 .
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 7904cb242f0529b897e23c3f0b3e008c__1712045160
URL1:https://arc.ask3.ru/arc/aa/79/8c/7904cb242f0529b897e23c3f0b3e008c.html
Заголовок, (Title) документа по адресу, URL1:
Forwarding (object-oriented programming) - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)