Dispatch в ООП: Динамическая привязка, Single и Double Dispatch
Dispatch — это механизм выбора конкретной реализации метода при его вызове. Выбор может происходить статически во время компиляции или динамически во время выполнения программы. Это основа полиморфизма.
Что такое Dispatch?
Dispatch разрешает вызов метода в конкретную реализацию. От способа этого разрешения зависит гибкость и производительность программы.
Виды Dispatch
- Статический Dispatch: решение принимается на этапе компиляции
- Динамический Dispatch: решение принимается во время выполнения
- Single Dispatch: выбор зависит от типа объекта-получателя
- Double Dispatch: выбор зависит от типов двух объектов
- Множественный Dispatch: выбор зависит от типов нескольких объектов
Статический и динамический Dispatch
Статический Dispatch (перегрузка)
public class StaticDispatchDemo {
// Переиспользуемые методы - статический dispatch
public static class Printer {
public void print(Object obj) {
System.out.println("Printing Object: " + obj.toString());
}
public void print(String str) {
System.out.println("Printing String: " + str);
}
public void print(Integer num) {
System.out.println("Printing Integer: " + num);
}
public void print(String str, int count) {
for (int i = 0; i < count; i++) {
System.out.println("String " + (i + 1) + ": " + str);
}
}
}
public static void demonstrateStaticDispatch() {
Printer printer = new Printer();
// Прямые вызовы - однозначный выбор
printer.print("Hello"); // print(String)
printer.print(42); // print(Integer)
printer.print("Test", 3); // print(String, int)
// Важный момент: статические типы решают!
Object obj1 = "Hello";
Object obj2 = 42;
printer.print(obj1); // print(Object) - компилятор видит только тип Object!
printer.print(obj2); // print(Object) - компилятор видит только тип Object!
// Приведение типа для выбора нужной перегрузки
printer.print((String) obj1); // print(String)
// printer.print((Integer) obj2); // ClassCastException во время выполнения!
}
}
Динамический Dispatch (переопределение)
public class DynamicDispatchDemo {
// Базовый класс с виртуальными методами
public static abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// Виртуальный метод - привязывается динамически
public String makeSound() {
return name + " makes a sound";
}
// Еще один виртуальный метод
public String move() {
return name + " moves";
}
// Финальный метод - нельзя переопределить
public final String getName() {
return name;
}
// Абстрактный метод - нужно переопределить
public abstract String getType();
}
// Конкретные подклассы
public static class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public String makeSound() {
return name + " barks: Woof!";
}
@Override
public String move() {
return name + " runs happily";
}
@Override
public String getType() {
return "Dog";
}
// Дополнительный метод
public String wagTail() {
return name + " wags tail excitedly";
}
}
public static class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public String makeSound() {
return name + " meows: Meow!";
}
@Override
public String move() {
return name + " sneaks silently";
}
@Override
public String getType() {
return "Cat";
}
public String purr() {
return name + " purrs contentedly";
}
}
public static class Bird extends Animal {
public Bird(String name) {
super(name);
}
@Override
public String makeSound() {
return name + " chirps: Tweet!";
}
@Override
public String move() {
return name + " flies gracefully";
}
@Override
public String getType() {
return "Bird";
}
public String sing() {
return name + " sings a beautiful song";
}
}
// Демонстрация динамического dispatch
public static void demonstrateDynamicDispatch() {
List<Animal> animals = new ArrayList<>();
animals.add(new Dog("Buddy"));
animals.add(new Cat("Whiskers"));
animals.add(new Bird("Tweety"));
System.out.println("=== Динамический Dispatch ===");
for (Animal animal : animals) {
// Динамическая привязка - решение принимается во время выполнения!
System.out.println(animal.getType() + ": " + animal.makeSound());
System.out.println(animal.getType() + ": " + animal.move());
System.out.println();
}
// Полиморфная обработка
processAnimal(animals.get(0)); // Dog
processAnimal(animals.get(1)); // Cat
processAnimal(animals.get(2)); // Bird
}
// Полиморфный метод
public static void processAnimal(Animal animal) {
System.out.println("Processing " + animal.getType());
// Динамический dispatch
String sound = animal.makeSound();
String movement = animal.move();
System.out.println(" Sound: " + sound);
System.out.println(" Movement: " + movement);
// Операции, специфичные для типа (с instanceof)
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
System.out.println(" Special: " + dog.wagTail());
} else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
System.out.println(" Special: " + cat.purr());
} else if (animal instanceof Bird) {
Bird bird = (Bird) animal;
System.out.println(" Special: " + bird.sing());
}
}
}
Single Dispatch
Как работает Single Dispatch
public class SingleDispatchDemo {
// Single Dispatch - только тип получателя имеет значение
public interface Shape {
double area();
double perimeter();
String getType();
void accept(ShapeVisitor visitor);
}
public static class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
@Override
public String getType() {
return "Circle";
}
@Override
public void accept(ShapeVisitor visitor) {
visitor.visitCircle(this); // Single Dispatch
}
public double getRadius() { return radius; }
}
public static class Rectangle implements Shape {
private double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double area() {
return width * height;
}
@Override
public double perimeter() {
return 2 * (width + height);
}
@Override
public String getType() {
return "Rectangle";
}
@Override
public void accept(ShapeVisitor visitor) {
visitor.visitRectangle(this); // Single Dispatch
}
public double getWidth() { return width; }
public double getHeight() { return height; }
}
public static class Triangle implements Shape {
private double base, height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
@Override
public double perimeter() {
// Упрощено: равносторонний треугольник
double side = base;
return 3 * side;
}
@Override
public String getType() {
return "Triangle";
}
@Override
public void accept(ShapeVisitor visitor) {
visitor.visitTriangle(this); // Single Dispatch
}
public double getBase() { return base; }
public double getHeight() { return height; }
}
// Демонстрация
public static void demonstrateSingleDispatch() {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(2.0));
shapes.add(new Rectangle(3.0, 4.0));
shapes.add(new Triangle(5.0, 3.0));
System.out.println("=== Single Dispatch ===");
for (Shape shape : shapes) {
System.out.println(shape.getType());
System.out.println(" Area: " + String.format("%.2f", shape.area()));
System.out.println(" Perimeter: " + String.format("%.2f", shape.perimeter()));
System.out.println();
}
}
}
Double Dispatch с помощью Visitor Pattern
Visitor Pattern для двойной диспетчеризации
public class DoubleDispatchDemo {
// Visitor Interface
public interface ShapeVisitor {
void visitCircle(Circle circle);
void visitRectangle(Rectangle rectangle);
void visitTriangle(Triangle triangle);
double getResult();
}
// Конкретный Visitor для расчёта площади
public static class AreaVisitor implements ShapeVisitor {
private double totalArea = 0.0;
@Override
public void visitCircle(Circle circle) {
double area = Math.PI * circle.getRadius() * circle.getRadius();
totalArea += area;
System.out.println("Circle area: " + String.format("%.2f", area));
}
@Override
public void visitRectangle(Rectangle rectangle) {
double area = rectangle.getWidth() * rectangle.getHeight();
totalArea += area;
System.out.println("Rectangle area: " + String.format("%.2f", area));
}
@Override
public void visitTriangle(Triangle triangle) {
double area = 0.5 * triangle.getBase() * triangle.getHeight();
totalArea += area;
System.out.println("Triangle area: " + String.format("%.2f", area));
}
@Override
public double getResult() {
return totalArea;
}
}
// Visitor для расчёта периметра
public static class PerimeterVisitor implements ShapeVisitor {
private double totalPerimeter = 0.0;
@Override
public void visitCircle(Circle circle) {
double perimeter = 2 * Math.PI * circle.getRadius();
totalPerimeter += perimeter;
System.out.println("Circle perimeter: " + String.format("%.2f", perimeter));
}
@Override
public void visitRectangle(Rectangle rectangle) {
double perimeter = 2 * (rectangle.getWidth() + rectangle.getHeight());
totalPerimeter += perimeter;
System.out.println("Rectangle perimeter: " + String.format("%.2f", perimeter));
}
@Override
public void visitTriangle(Triangle triangle) {
double perimeter = 3 * triangle.getBase(); // Упрощённо
totalPerimeter += perimeter;
System.out.println("Triangle perimeter: " + String.format("%.2f", perimeter));
}
@Override
public double getResult() {
return totalPerimeter;
}
}
// Visitor для экспорта в XML
public static class XMLExportVisitor implements ShapeVisitor {
private StringBuilder xml = new StringBuilder();
@Override
public void visitCircle(Circle circle) {
xml.append("<shape type=\"circle\">\n");
xml.append(" <radius>").append(circle.getRadius()).append("</radius>\n");
xml.append(" <area>").append(String.format("%.2f", Math.PI * circle.getRadius() * circle.getRadius())).append("</area>\n");
xml.append("</shape>\n");
}
@Override
public void visitRectangle(Rectangle rectangle) {
xml.append("<shape type=\"rectangle\">\n");
xml.append(" <width>").append(rectangle.getWidth()).append("</width>\n");
xml.append(" <height>").append(rectangle.getHeight()).append("</height>\n");
xml.append(" <area>").append(String.format("%.2f", rectangle.getWidth() * rectangle.getHeight())).append("</area>\n");
xml.append("</shape>\n");
}
@Override
public void visitTriangle(Triangle triangle) {
xml.append("<shape type=\"triangle\">\n");
xml.append(" <base>").append(triangle.getBase()).append("</base>\n");
xml.append(" <height>").append(triangle.getHeight()).append("</height>\n");
xml.append(" <area>").append(String.format("%.2f", 0.5 * triangle.getBase() * triangle.getHeight())).append("</area>\n");
xml.append("</shape>\n");
}
@Override
public double getResult() {
return 0; // Не используется для этого Visitor
}
public String getXML() {
return "<shapes>\n" + xml.toString() + "</shapes>";
}
}
// Демонстрация двойной диспетчеризации
public static void demonstrateDoubleDispatch() {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(2.0));
shapes.add(new Rectangle(3.0, 4.0));
shapes.add(new Triangle(5.0, 3.0));
System.out.println("=== Double Dispatch с Visitor Pattern ===");
// Area Visitor
System.out.println("Расчёт площади:");
AreaVisitor areaVisitor = new AreaVisitor();
for (Shape shape : shapes) {
shape.accept(areaVisitor); // Double Dispatch!
}
System.out.println("Общая площадь: " + String.format("%.2f", areaVisitor.getResult()));
System.out.println();
// Perimeter Visitor
System.out.println("Расчёт периметра:");
PerimeterVisitor perimeterVisitor = new PerimeterVisitor();
for (Shape shape : shapes) {
shape.accept(perimeterVisitor); // Double Dispatch!
}
System.out.println("Общий периметр: " + String.format("%.2f", perimeterVisitor.getResult()));
System.out.println();
// XML Export Visitor
System.out.println("Экспорт в XML:");
XMLExportVisitor xmlVisitor = new XMLExportVisitor();
for (Shape shape : shapes) {
shape.accept(xmlVisitor); // Double Dispatch!
}
System.out.println(xmlVisitor.getXML());
}
}
Множественная диспетчеризация (Multiple Dispatch)
Имитация множественной диспетчеризации
public class MultipleDispatchDemo {
// Задача: операции, зависящие от двух типов
public interface Collider {
void collideWith(Collider other);
String getType();
}
public static class Asteroid implements Collider {
private String name;
private double mass;
public Asteroid(String name, double mass) {
this.name = name;
this.mass = mass;
}
@Override
public void collideWith(Collider other) {
// Single Dispatch - определяется только тип другого объекта
System.out.println(name + " collides with " + other.getType());
}
@Override
public String getType() {
return "Asteroid";
}
public double getMass() { return mass; }
public String getName() { return name; }
}
public static class Spaceship implements Collider {
private String name;
private double shield;
public Spaceship(String name, double shield) {
this.name = name;
this.shield = shield;
}
@Override
public void collideWith(Collider other) {
// Single Dispatch - проблема: мы не знаем точный тип объекта
System.out.println(name + " collides with " + other.getType());
}
@Override
public String getType() {
return "Spaceship";
}
public double getShield() { return shield; }
public String getName() { return name; }
}
public static class SpaceStation implements Collider {
private String name;
private double hull;
public SpaceStation(String name, double hull) {
this.name = name;
this.hull = hull;
}
@Override
public void collideWith(Collider other) {
System.out.println(name + " collides with " + other.getType());
}
@Override
public String getType() {
return "SpaceStation";
}
public double getHull() { return hull; }
public String getName() { return name; }
}
// Решение с помощью Double Dispatch Pattern
public interface CollisionHandler {
void handleAsteroidAsteroid(Asteroid a1, Asteroid a2);
void handleAsteroidSpaceship(Asteroid asteroid, Spaceship spaceship);
void handleAsteroidStation(Asteroid asteroid, SpaceStation station);
void handleSpaceshipSpaceship(Spaceship s1, Spaceship s2);
void handleSpaceshipStation(Spaceship spaceship, SpaceStation station);
void handleStationStation(SpaceStation s1, SpaceStation s2);
}
public static class DefaultCollisionHandler implements CollisionHandler {
@Override
public void handleAsteroidAsteroid(Asteroid a1, Asteroid a2) {
double totalMass = a1.getMass() + a2.getMass();
System.out.println("Asteroid collision: " + a1.getName() + " + " + a2.getName() +
" (total mass: " + String.format("%.1f", totalMass) + ")");
}
@Override
public void handleAsteroidSpaceship(Asteroid asteroid, Spaceship spaceship) {
double damage = asteroid.getMass() * 0.1;
spaceship.setShield(spaceship.getShield() - damage);
System.out.println("Asteroid-Spaceship collision: " + asteroid.getName() +
" hits " + spaceship.getName() + " (damage: " +
String.format("%.1f", damage) + ")");
}
@Override
public void handleAsteroidStation(Asteroid asteroid, SpaceStation station) {
double damage = asteroid.getMass() * 0.05;
station.setHull(station.getHull() - damage);
System.out.println("Asteroid-Station collision: " + asteroid.getName() +
" hits " + station.getName() + " (damage: " +
String.format("%.1f", damage) + ")");
}
@Override
public void handleSpaceshipSpaceship(Spaceship s1, Spaceship s2) {
System.out.println("Spaceship collision: " + s1.getName() + " + " + s2.getName());
}
@Override
public void handleSpaceshipStation(Spaceship spaceship, SpaceStation station) {
System.out.println("Spaceship-Station collision: " + spaceship.getName() +
" docks at " + station.getName());
}
@Override
public void handleStationStation(SpaceStation s1, SpaceStation s2) {
System.out.println("Station collision: " + s1.getName() + " + " + s2.getName());
}
}
// Улучшенные Collider с двойной диспетчеризацией
public static class ImprovedAsteroid extends Asteroid {
public ImprovedAsteroid(String name, double mass) {
super(name, mass);
}
@Override
public void collideWith(Collider other) {
other.collideWithAsteroid(this); // Обратный вызов для Double Dispatch
}
public void collideWithAsteroid(Asteroid other) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleAsteroidAsteroid(this, other);
}
public void collideWithSpaceship(Spaceship spaceship) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleAsteroidSpaceship(this, spaceship);
}
public void collideWithStation(SpaceStation station) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleAsteroidStation(this, station);
}
}
public static class ImprovedSpaceship extends Spaceship {
public ImprovedSpaceship(String name, double shield) {
super(name, shield);
}
@Override
public void collideWith(Collider other) {
other.collideWithSpaceship(this);
}
public void collideWithAsteroid(Asteroid asteroid) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleAsteroidSpaceship(asteroid, this);
}
public void collideWithSpaceship(Spaceship other) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleSpaceshipSpaceship(this, other);
}
public void collideWithStation(SpaceStation station) {
CollisionHandler handler = new DefaultCollisionHandler();
handler.handleSpaceshipStation(this, station);
}
}
// Демонстрация
public static void demonstrateMultipleDispatch() {
System.out.println("=== Имитация Multiple Dispatch ===");
// Простая Single Dispatch (проблема)
System.out.println("Single Dispatch (проблема):");
Collider asteroid1 = new Asteroid("Rocky", 100.0);
Collider spaceship1 = new Spaceship("Explorer", 50.0);
asteroid1.collideWith(spaceship1); // Известен только тип spaceship1
System.out.println();
// Решение с Double Dispatch
System.out.println("Решение с Double Dispatch:");
ImprovedAsteroid asteroid2 = new ImprovedAsteroid("Rocky", 100.0);
ImprovedSpaceship spaceship2 = new ImprovedSpaceship("Explorer", 50.0);
asteroid2.collideWith(spaceship2); // Известны оба типа!
System.out.println();
// Более сложные столкновения
List<Collider> objects = Arrays.asList(
new ImprovedAsteroid("Rocky", 100.0),
new ImprovedSpaceship("Explorer", 50.0),
new ImprovedSpaceship("Voyager", 60.0),
new SpaceStation("Alpha", 200.0)
);
System.out.println("Complex collisions:");
for (int i = 0; i < objects.size(); i++) {
for (int j = i + 1; j < objects.size(); j++) {
objects.get(i).collideWith(objects.get(j));
}
}
}
}
Виртуальные таблицы методов (vtable)
Как работают vtable
public class VTableDemo {
// Vereinfachte Darstellung einer vtable
public static class VTableVisualization {
// Basisklasse
public static class Base {
// Virtuelle Methoden
public virtual void method1() { System.out.println("Base.method1"); }
public virtual void method2() { System.out.println("Base.method2"); }
// Konkrete Methode
public void concreteMethod() { System.out.println("Base.concreteMethod"); }
}
// Abgeleitete Klasse 1
public static class Derived1 extends Base {
@Override
public void method1() { System.out.println("Derived1.method1"); }
// method2 geerbt
@Override
public void method2() { System.out.println("Derived1.method2"); }
}
// Abgeleitete Klasse 2
public static class Derived2 extends Base {
// method1 geerbt
@Override
public void method2() { System.out.println("Derived2.method2"); }
public void method3() { System.out.println("Derived2.method3"); }
}
// Demonstration der vtable
public static void demonstrateVTable() {
System.out.println("=== VTable Demonstration ===");
Base base = new Base();
Base derived1 = new Derived1();
Base derived2 = new Derived2();
// Vtable für Base:
// [Base.method1, Base.method2]
System.out.println("Base object:");
base.method1(); // Base.method1
base.method2(); // Base.method2
// Vtable für Derived1:
// [Derived1.method1, Derived1.method2]
System.out.println("\nDerived1 object:");
derived1.method1(); // Derived1.method1
derived1.method2(); // Derived1.method2
// Vtable für Derived2:
// [Base.method1, Derived2.method2]
System.out.println("\nDerived2 object:");
derived2.method1(); // Base.method1 (geerbt)
derived2.method2(); // Derived2.method2
// Konkrete Methode - nicht in vtable
System.out.println("\nConcrete method:");
base.concreteMethod();
derived1.concreteMethod();
derived2.concreteMethod();
}
}
// Performance-Vergleich
public static class PerformanceComparison {
// Finale Methode - kein virtueller Aufruf
public static class FinalClass {
public final void finalMethod() {
// Kein vtable Lookup
}
}
// Virtuelle Methode - vtable Lookup
public static class VirtualClass {
public void virtualMethod() {
// vtable Lookup erforderlich
}
}
public static void performanceTest() {
FinalClass finalObj = new FinalClass();
VirtualClass virtualObj = new VirtualClass();
int iterations = 100_000_000;
// Test finale Methode
long start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
finalObj.finalMethod();
}
long finalTime = System.nanoTime() - start;
// Test virtuelle Methode
start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
virtualObj.virtualMethod();
}
long virtualTime = System.nanoTime() - start;
System.out.println("Performance Comparison:");
System.out.println("Final method: " + (finalTime / 1_000_000) + " ms");
System.out.println("Virtual method: " + (virtualTime / 1_000_000) + " ms");
System.out.println("Difference: " + ((virtualTime - finalTime) / 1_000_000) + " ms");
}
}
}
Dispatch в реальных приложениях
Пример из фреймворка: система плагинов
public class PluginDispatchDemo {
// Plugin Interface
public interface Plugin {
void initialize();
void execute();
void shutdown();
String getName();
String getVersion();
}
// Abstrakte Basisklasse für Plugins
public abstract class AbstractPlugin implements Plugin {
protected String name;
protected String version;
public AbstractPlugin(String name, String version) {
this.name = name;
this.version = version;
}
@Override
public final String getName() {
return name;
}
@Override
public final String getVersion() {
return version;
}
// Template Method Pattern
@Override
public final void execute() {
System.out.println("Executing plugin: " + name);
try {
doExecute();
System.out.println("Plugin execution completed: " + name);
} catch (Exception e) {
System.err.println("Plugin execution failed: " + name + " - " + e.getMessage());
}
}
// Abstrakte Methode für konkrete Implementierung
protected abstract void doExecute();
// Standardimplementierungen
@Override
public void initialize() {
System.out.println("Initializing plugin: " + name);
}
@Override
public void shutdown() {
System.out.println("Shutting down plugin: " + name);
}
}
// Konkrete Plugins
public static class DatabasePlugin extends AbstractPlugin {
public DatabasePlugin() {
super("DatabasePlugin", "1.0.0");
}
@Override
protected void doExecute() {
System.out.println(" Connecting to database...");
System.out.println(" Executing database operations...");
System.out.println(" Closing database connection...");
}
@Override
public void initialize() {
super.initialize();
System.out.println(" Loading database driver...");
}
}
public static class LoggingPlugin extends AbstractPlugin {
public LoggingPlugin() {
super("LoggingPlugin", "2.1.0");
}
@Override
protected void doExecute() {
System.out.println(" Setting up loggers...");
System.out.println(" Configuring log levels...");
System.out.println(" Starting log rotation...");
}
@Override
public void shutdown() {
System.out.println(" Flushing log buffers...");
super.shutdown();
}
}
public static class SecurityPlugin extends AbstractPlugin {
public SecurityPlugin() {
super("SecurityPlugin", "1.5.2");
}
@Override
protected void doExecute() {
System.out.println(" Initializing security manager...");
System.out.println(" Setting up authentication...");
System.out.println(" Configuring authorization rules...");
}
}
// Plugin Manager mit Dispatch
public static class PluginManager {
private List<Plugin> plugins = new ArrayList<>();
public void registerPlugin(Plugin plugin) {
plugins.add(plugin);
plugin.initialize();
}
public void executeAllPlugins() {
System.out.println("=== Executing all plugins ===");
for (Plugin plugin : plugins) {
plugin.execute(); // Dynamischer Dispatch
}
}
public void shutdownAllPlugins() {
System.out.println("\n=== Shutting down all plugins ===");
for (Plugin plugin : plugins) {
plugin.shutdown(); // Dynamischer Dispatch
}
}
public void executePluginByName(String name) {
for (Plugin plugin : plugins) {
if (plugin.getName().equals(name)) {
plugin.execute(); // Dynamischer Dispatch
return;
}
}
System.out.println("Plugin not found: " + name);
}
public void listPlugins() {
System.out.println("=== Registered Plugins ===");
for (Plugin plugin : plugins) {
System.out.println(plugin.getName() + " v" + plugin.getVersion());
}
}
}
// Demonstration
public static void demonstratePluginSystem() {
PluginManager manager = new PluginManager();
// Plugins registrieren
manager.registerPlugin(new DatabasePlugin());
manager.registerPlugin(new LoggingPlugin());
manager.registerPlugin(new SecurityPlugin());
// Alle Plugins ausführen
manager.listPlugins();
manager.executeAllPlugins();
// Spezifisches Plugin ausführen
System.out.println("\n=== Executing specific plugin ===");
manager.executePluginByName("LoggingPlugin");
// Aufräumen
manager.shutdownAllPlugins();
}
}
Best Practices для Dispatch
1. Final для производительности
public class DispatchBestPractices {
// Финальные методы для производительности
public static class PerformanceOptimized {
// Финальный метод - без виртуального вызова
public final void criticalMethod() {
// Hot Path Code
}
// Финальный класс - наследование невозможно
public static final class ImmutableData {
private final int value;
public ImmutableData(int value) {
this.value = value;
}
public final int getValue() {
return value;
}
}
}
// Интерфейс для гибкости
public interface Processor {
void process();
}
// Конкретная реализация
public static class FastProcessor implements Processor {
@Override
public void process() {
// Реализация
}
}
}
2. Избежание проблем с Dispatch
public class DispatchProblems {
// Проблема: перегрузка с типами ссылок
public static class ProblematicOverloading {
public void process(Object obj) {
System.out.println("Processing Object");
}
public void process(String str) {
System.out.println("Processing String");
}
public void demonstrateProblem() {
Object obj = "Hello";
process(obj); // Вызывает process(Object)!
}
}
// Решение: понятные имена методов
public static class Solution {
public void processObject(Object obj) {
System.out.println("Processing Object");
}
public void processString(String str) {
System.out.println("Processing String");
}
public void demonstrateSolution() {
Object obj = "Hello";
if (obj instanceof String) {
processString((String) obj);
} else {
processObject(obj);
}
}
}
}
Концепции для экзамена
Важные различия
-
Статический против динамического
- Статический: время компиляции (перегрузка)
- Динамический: время выполнения (переопределение)
-
Single против Double Dispatch
- Single: один тип объекта определяет решение
- Double: два типа объектов определяют решение
-
vtable против Early Binding
- vtable: виртуальные методы
- Early Binding: финальные методы
Типовые экзаменационные задачи
- Объясните Single vs Double Dispatch
- Реализуйте паттерн Visitor
- Сравните статическую и динамическую привязку
- Опишите механизм работы vtable
- Разрешите проблемы с Dispatch
Итого
Dispatch является фундаментом объектно-ориентированного программирования:
- Статический Dispatch: предсказуемый, быстрый (перегрузка)
- Динамический Dispatch: гибкий, расширяемый (переопределение)
- Single Dispatch: стандарт в большинстве OOP-языков
- Double Dispatch: реализуется через паттерн Visitor
- vtables: эффективная реализация динамического Dispatch
Правильное применение Dispatch обеспечивает гибкие, поддерживаемые и производительные архитектуры программного обеспечения.
Продолжение в курсе OOP
Все статьи про OOP теперь завершены. Вернитесь к первой статье: Основы объектно-ориентированного программирования OOP.

