DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
11 Monitoring and Observability Tools for 2023
Learn more
  1. DZone
  2. Coding
  3. Languages
  4. Double Dispatch: the next best thing with respect to Dependency Injection

Double Dispatch: the next best thing with respect to Dependency Injection

Giorgio Sironi user avatar by
Giorgio Sironi
·
Dec. 07, 10 · Interview
Like (0)
Save
Tweet
Share
15.68K Views

Join the DZone community and get the full member experience.

Join For Free

Object-oriented languages, like C++, Java and PHP, implement what is called single dispatch: when you have an object in a variable and you call a method on this variable, the message is dispatched to the right class at runtime, even if when you write the code you do not want to tie the call to a particular implementation. Polymorphism is an example of this mechanism in action.

Double Dispatch meaning

Double Dispatch is a simple idea: change behavior also depending on the caller's class, and not only on the called class. Why we would want to do that?

Wikipedia makes the example of adaptive collision algorithms, that calculate the result of the collision between two objects. The laws of physics prescribe that the collision depend on the characteristics of the two objects, so when we collide an Asteroid with a Spaceship we may want to reach a different outcome when the Asteroid is an instance of the subclass GiantAsteroid, or the Spaceship is an instance of the subclass GiantSpaceship.

With a more mundane example, we want something like this:

class NotNullValidator
{
public function isValid(ValidableEntity $entity)
{
return $entity->isValid();
}
}
$validator = new NotNullValidator();
$entity = new User();
var_dump($validator->isValid());
to produce this output:
User-specific code can be inserted here.
NotNullValidator-specific code can be inserted here.

With the initial design, we can only achieve this by adding code to the NotNullValidator class. The point however is instead: how can we make the User::isValid() method, which is resolved by the language to be used when ValidableEntity $entity happens to be an User, to recognize that it was called by NotNullValidator and not from something else? We want to encapsulate this "choice of caller" into the User class, for example because it needs access to the User's private fields, a trait which defines a line of code as belonging to the User class and not to anyone else.

Double Dispatch implementation

I anticipate that the way to go is to transform the caller also in a parameter. Even if the language used does not support parameters overloading to support variations on the caller class, we can easily forward the call to the parameter and use simple dispatch again.

Even in the languages where overloading is available, like C, it is usually not done dinamically (like for virtual methods) and the method to call is selected at compile time, basing on the reference variable. This means that in C the User object, pointed by an handler of type ValidableEntity, will only select the method which takes ValidableEntity as an argument for dispatch, even if multiple overloaded version of the method are available.

Mormally, OO languages only support single dispatch: the actual method called varies on the class of the called object, but has no way to distinguish between the calling ones. As simple, I mean different from an hack that involves the stack trace. Therefore, Double Dispatch is implemented via the Visitor pattern for the majority of object-oriented languages.

Practical usage

When Double Dispatch comes handy? It is a common solution for providing collaborators to Entity classes (e.g. User, Post, Group, Article...) of a Domain Model.
Usually we cannot inject collaborators in such classes, since the ORM won't now how to reconstitute the objects unless you configure some listener that is passed each reconstituted object. This is true in the case of Active Records (even if the Entity term is wasted in that case) and also if the ORM is a Data Mapper. The User class of the example can implement Double Dispatch instead: in this case, one dispatch is done over the $user variable and the other one over the collaborator, which is passed as a parameter. The collaborator does not need to also be the caller, only to be passed to the Entity in the signature of the method where it is needed.

<?php
/**
* An Element in the Visitor pattern implementation.
*/
interface ValidableEntity
{
public function isValid(Validator $validator);
}

class User implements ValidableEntity
{
private $name = 'Giorgio';

public function isValid(Validator $validator)
{
echo "User-specific code can be inserted here.\n";
return $validator->validate(array('name' => $this->name));
}
}

/**
* Validators are Visitors, but implemented in the push style:
* the ValidableEntity only passes the necessary values to the Visitor.
*/
interface Validator
{
public function validate($values);
}

class NotNullValidator implements Validator
{
public function validate($values)
{
echo "NotNullValidator-specific code can be inserted here.\n";
foreach ($values as $fieldName => $eachValue) {
if ($eachValue === null) {
return false;
}
}
return true;
}

/**
* This is the entry point: we implement Double Dispatch by passing the caller
* object to the called one, so that the called can call a method on the original
* caller and take advatange of the method resolution supported by the language.
* The sum of two simple dispatches is a Double Dispatch. In the pattern's
* terminology, the Visitor is also the Client.
*/
public function isValid(ValidableEntity $entity)
{
return $entity->isValid($this);
}
}

$user = new User();
$validator = new NotNullValidator(/* collaborators can be injected here */);
var_dump($validator->isValid($user));

The advantages

With Double Dispatch, of course we do not need to inject other objects in Entities, which I came to think is not a Domain-Driven Design practice. Injecting would also be not very appropriate, since this kind of dependencies is used only in one or two methods (as in the example, for validation related ones).

The Api of the Entity becomes complete: everything you need is present as a method on the Entity, which is therefore not so anemic as in the case of external objects handling its logic. In our original example, the validation methods are present on the Entity and not on the Validator: this design is positively different from a Validator having to access the User's data by reflection or some privileged public method.

The Entity can pass to the Visitor only the necessary private data, so that its encapsulation is not violated. In the example, User passed the values of its private fields, which shouldn't be exposed anywhere. Moreover, the dependency on the collaborator is clearly visible: it's in the method signature. This is a step forward from the inserting a new Collaborator() into the Entity itself.

Conclusion

The only downside is that the caller of the Entity Api must be injected with the collaborator to be able to pass it to the Entity itself. Still, we cannot totally hide a dependency: it has to be injected somewhere, and not having an available Entity constructor, Double Dispatch gives us a standard solution as the next best thing with respect to DI.

References:

http://en.wikipedia.org/wiki/Double_dispatch

http://misko.hevery.com/2009/07/31/how-to-think-about-oo/

http://c2.com/cgi/wiki?DoubleDispatch

Double dispatch Dependency injection entity Object (computer science)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Custom Validators in Quarkus
  • 5 Steps for Getting Started in Deep Learning
  • What’s New in the Latest Version of Angular V15?
  • Steel Threads Are a Technique That Will Make You a Better Engineer

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: