Мультиметод

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

Мультиме́тод (англ. multimethod) или мно́жественная диспетчериза́ция (англ. multiple dispatch) — механизм, позволяющий выбрать одну из нескольких функций в зависимости от динамических типов или значений аргументов. Представляет собой расширение одиночной диспетчеризации (виртуальных функций), где выбор метода осуществляется динамически на основе фактического типа объекта. Множественная диспетчеризация обобщает динамическую диспетчеризацию для случаев с двумя или более объектами.

В явном виде мультиметоды поддерживаются «объектной системой Common Lisp’а» (CLOS).

Пример[править | править вики-текст]

Для лучшего понимания разницы между мультиметодами и одиночной диспетчеризацией можно продемонстрировать следующий пример. Представим себе игру, в которой, наряду с разнообразными другими объектами, присутствуют астероиды и космические корабли. Когда два каких-либо объекта сталкиваются, программа должна выбрать какой-либо определенный алгоритм действий, в зависимости от того, что столкнулось с чем.

В языке с поддержкой мультиметодов, таком, как Common Lisp, код выглядел бы вот так:

(defgeneric collide (x y))
 
(defmethod collide ((x asteroid) (y asteroid))
  ;;астероид сталкивается с астероидом
  )
 
(defmethod collide ((x asteroid) (y spaceship))
  ;;астероид сталкивается с космическим кораблем
  )
 
(defmethod collide ((x spaceship) (y asteroid))
  ;;космический корабль сталкивается с астероидом
  )
 
(defmethod collide ((x spaceship) (y spaceship))
  ;;космический корабль сталкивается с космическим кораблем
  )

Реализация на C# 4.0, с использованием dynamic типов:

class Program
{
  class Thing { }
  class Asteroid : Thing { }
  class Spaceship : Thing { }
 
  static void CollideWithImpl(Asteroid x, Asteroid y) 
  {
    // астероид сталкивается с астероидом
  }
 
  static void CollideWithImpl(Asteroid x, Spaceship y) 
  {
    // астероид сталкивается с космическим кораблем
  }
 
  static void CollideWithImpl(Spaceship x, Asteroid y) 
  {
    // космический корабль сталкивается с астероидом
  }
 
  static void CollideWithImpl(Spaceship x, Spaceship y) 
  {
    // космический корабль сталкивается с космическим кораблем
  }
 
  static void CollideWith(Thing x, Thing y)
  {
    dynamic a = x;
    dynamic b = y;
    CollideWithImpl(a, b);
  }
 
  static void Main(string[] args)
  {
    var asteroid = new Asteroid();
    var spaceship = new Spaceship();
    CollideWith(asteroid, spaceship);
    CollideWith(spaceship, spaceship);
  }
}

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

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

public abstract class Thing {
    public abstract void collide(Thing thing);
 
    protected abstract void collideWithAsteroid(Asteroid asteroid);
    protected abstract void collideWithSpaceship(Spaceship spaceship);
}
 
public class Asteroid extends Thing {
    @Override
    public void collide(Thing thing) {
        // Вторая диспетчеризация
        thing.collideWithAsteroid(this);
    }
 
    @Override
    protected void collideWithAsteroid(Asteroid asteroid) {
        // астероид сталкивается с астероидом
    }
 
    @Override
    protected void collideWithSpaceship(Spaceship spaceship) {
        // космический корабль сталкивается с астероидом
    }
}
 
public class Spaceship extends Thing {
    @Override
    public void collide(Thing thing) {
        // Вторая диспетчеризация
        thing.collideWithSpaceship(this);
    }
 
    @Override
    protected void collideWithAsteroid(Asteroid asteroid) {
        // астероид сталкивается с космическим кораблем
    }
 
    @Override
    protected void collideWithSpaceship(Spaceship spaceship) {
        // космический корабль сталкивается с космическим кораблем
    }
}
 
public class Main {
    public static void main(String[] args) {
        Asteroid asteroid = new Asteroid();
        Spaceship spaceship = new Spaceship();
        asteroid.collide(spaceship);
        spaceship.collide(spaceship);
    }
}