1
class Product
{
}

class Mobile extends Product
{
}

class Market
{
    public void buy(Product product)
    {
        System.out.println("Search a product in market");
    }

    public void buy(Mobile mobile)
    {
        System.out.println("Search a mobile in market");
    }
}

class Shop extends Market
{

    public void buy(Product product)
    {
        System.out.println("Search a product in shop");
    }

    public void buy(Mobile mobile)
    {
        System.out.println("Search a mobile in shop.");
    }
}

public class DoubleDispatchExample 
{

    public static void main(String[] args)
    {
        Market market = new Market();
        Market shop = new Shop();

        market.buy(new Product());
        shop.buy(new Mobile());
     }
}

上述程序的输出是:

在市场上搜索产品。

在商店中搜索手机。

因此,输出暗示调用 market.buy(new Product()); 和 shop.buy(new Mobile()); 由调用它的对象的引用和传递给它的参数来解决。所以如果它同时使用这两个东西来调度一个函数调用,我们可以称之为双重调度吗?还是我误解了双重派遣一词?

4

1 回答 1

0

什么是双重派送?

根据定义,双重分派是

根据调用中涉及的两个对象的运行时类型,将函数调用分派到不同的具体函数的机制。

你们的派遣是如何运作的?

你有两个对象:

  • 类型之一Market(或派生类型,例如Shop);
  • 类型之一Product(或派生类型,例如Mobile)。

您正在使用动态的单一调度来调用正确的buy()方法,具体取决于调用该方法的对象的动态类型:

market.buy(...);  // invokes the Market version of buy()
shop.buy(...);    // invokes the Shop version of buy()

您正在使用重载来根据方法的参数选择正确的buy()方法变体:

public void buy(Product product)   // depends on argument's type
public void buy(Mobile mobile)     //    "             "

这是动态调度吗?

不幸的是,用于选择重载函数的参数类型不是运行时参数类型,而是编译时静态类型。

尝试例如(在线演示):

Product p1 = new Product(); 
Product p2 = new Mobile();    
shop.buy(p1);
shop.buy(p2);
p1 = p2;
shop.buy(p1);

这将导致:

Search a product in shop
Search a product in shop
Search a product in shop

因此,您的代码的行为仅取决于对象的一种运行时类型,而不是两种运行时类型,它不是真正的双重分派

如何实现动态调度?

您可以使用使用重载和覆盖的弹跳方法,以便在两个对象中组合动态调度:

class Product
{
    public void buy(Market m)
    {
        System.out.println("Search a product in market");
    }
    public void buy(Shop s)
    {
        System.out.println("Search a product in shop");
    }
}
class Mobile extends Product
{
    ... // implement the Mobile version of the two functions
}
class Market
{
    public void buy(Product product)
    {
        product.buy (this);  // this use overload, but is not seen by caller
    }
}
class Shop extends Market
{
    public void buy(Product product)
    {
        product.buy (this);   // attention: this has another type here !!
    }
}

当你打电话时:

shop.buy(p1);

将会有一个基于真实类型shop(例如Shopor Market)的动态调度。这将使用重载来调用buy()根据动态类型选择的权利p1

在线演示在这里

另一种更复杂的方法可能是使用将类型组合与特定可调用对象相关联的映射。然后,您的代码将使用反射来确定参数的动态类型,以便找到要调用的正确可调用对象。这种方式也可以用于多次分派

于 2017-09-30T15:58:55.913 回答