8

For those that are familiar with the Mediator pattern...

I want to implement the Mediator pattern in Delphi, but the Delphi compiler can't handle the circular references required.

Looking at the original GOF diagram from 'Design Patterns', the Mediator has a reference to each Colleague, but many of the Colleague objects have a reference back to the Mediator.

This is not a problem in most languages, but my Delphi compiler is giving me 'F2047 Circular unit reference to ...'

Would this approach, using interfaces, be any use? (seems complicated)

I am using Delphi 2010

[Summary of solution]

Just to summarise the accepted answer: In languages that allow circular references, you can omit the abstract Mediator class (as discussed in the "Implementation" section of GoF on page 278). The only way you can implement Mediator in Delphi without an abstract Mediator class is to have all your Classes in one Unit.

Otherwise, you need an extra abstract Mediator base class in addition to the concrete subclass.

Your Uses clauses for the three Units would look like this:

ConcreteColleage1 Uses Mediator
ConcreteMediator Uses Mediator, ConcreateColleague1
Mediator (Doesn't use either)

No circular references!

Community
  • 1
  • 1
awmross
  • 3,789
  • 3
  • 38
  • 51

3 Answers3

7

Using interfaces can certainly help to decrease the dependencies between units. Another approach is to have abstract base classes which define the interaction methods between the classes and then put concrete descendants in separate units.

See: How to avoid circular unit reference? for more information on how to avoid circulare references in Delphi.

Community
  • 1
  • 1
Marjan Venema
  • 19,136
  • 6
  • 65
  • 79
5

I don't see where the circular dependencies arise. If you implement your classes following this diagram, no such thing should happen.

To implement this diagram in Delphi, you will indeed need to write

  • either a Mediator interface (and have your ConcreteMediator class implement this interface)
  • or a base Mediator class with virtual methods, (and have your ConcreteMediator class derive from Mediator and override these methods).
LeGEC
  • 46,477
  • 5
  • 57
  • 104
  • I'm referring to the Mediator pattern as described in the Design Patterns book by GoF. Specifically, the diagram on page 274. 'aButton' has a reference to 'aFontDialogDirector' and conversely, 'aFontDialogDirector' has a reference to 'aButton'. So in Delphi, these two classes have to be in the same Unit. – awmross Feb 14 '11 at 06:03
  • After reading your answer more carefully, I now see this is right. I have to create a base Mediator class in one Unit and subclass it in another Unit. If you edit your answer I can change my downvote to an upvote :-) – awmross Feb 14 '11 at 23:19
2

Another option to consider is to place Mediator and Colleague in the same unit. In many situations that is the idiomatic Delphi way to avoid circular references.

Using interfaces is often a good approach to this sort of problem but sometimes it can result in extra complexity for no real gain.

It's hard to know where the tradeoffs would fall for your code so I wouldn't like to state that one approach is better than the other as a general rule.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Since I am trying to break up a 5000 line file, keeping the classes in the same Unit doesn't help me much. But in other situations this would be a possible solution. – awmross Feb 14 '11 at 23:32
  • 2
    @awmross 5000 lines?! That's nothing, my biggest has 32,000 lines. More seriously, splitting up large files is often a good idea, but there always comes a point when it makes things worse by keeping things that are closely related apart from each other. Anyway, I'm sure you are well aware of this. – David Heffernan Feb 14 '11 at 23:37