Technical articles, including those at About Visual Basic, usually discuss the detailed syntax of VB.NET, not the overall philosophy of why you might want to do things in a certain way. Design Patterns, on the other hand, are all about the why and how of programming, not the syntax. This article, one of a series about design patterns in VB.NET, discusses a design pattern that you might have thought you already knew about, the Delegation pattern.
The general topic of design is one that usually turns to "design patterns". If you think syntax is hard, you have another page to turn. There are dozens of design patterns and a lot of books get written about them. In fact, you could do a lot worse than the (somewhat dated now) book Visual Basic Design Patterns.
Just to be clear, "Design Patterns" are actual code prototypes. A book like Fred Brooks' classic The Design of Design is about the overall management of the process.
"Design patterns" are not standards. Even the names vary among design gurus and variations also exist in how they're implemented. But there is quite a bit of broad agreement about the overall structure of design patterns and learning about them beats reinventing the wheel every time.
This is part 1 of a three part series about the Delegation design pattern. Part 1 (this part) shows you the general case using a pattern that can be found in a number of different sources. But this "general case" can be difficult to visualize. So part 2 - Inheritance as an alternative to the Delegation design pattern - shows you a program coded as closely as possible but using the familiar inheritance based logic to do the job. Then part 3 - A real world delegation design pattern - shows how this can solve the problem that came up when inheritance was used.
The Delegation Pattern - The General Case
A common definition of the Delegation pattern goes like this:
The delegation pattern is a design pattern in object-oriented programming where an object, instead of performing one of its stated tasks, delegates that task to an associated helper object.
VB.NET features a technology called Delegate that is essential in event handling. The familiar "Handles" clause is part of the VB.NET delegates technology; and it's an example of the delegation design pattern ... sort of. (More on this just a little later.)
About Visual Basic has a full article on delegates: Using Delegates in Visual Basic .NET for Runtime Flexibility. In that article, I note that, "Delegate" is a name used to describe procedures."
The code example in that article that declares an object as a delegate looks like this.
Public Delegate Function myFirstDelegate(ByVal a As Integer) As Integer
Later, a function named aFunc can be declared to be of type "myFirstDelegate".
Dim myDel As myFirstDelegate myDel = New myFirstDelegate(AddressOf aFunc)
Other code in your program can then hand off work to the aFunc procedure when myDel is used. The article goes into this is much more detail, and that isn't the subject of this article ... directly.
As it turns out, the Delegation design pattern does much the same thing, but it doesn't depend on any VB.NET "delegate" code to do it. Since we don't depend on VB.NET specific keywords, the Delegation design pattern can be used in most languages.
If you look up "Delegation Design Pattern" in Wikipedia, you can find code examples in Java, Eiffel, Perl, Ruby, and many others but not in VB.NET. This article corrects that oversight. Here is essentially the same example used there, but coded in VB.NET.
Module Module1 Public Interface I Sub F() Sub G() End Interface Public Class Program Public Shared Sub Main() Dim c As New C() c.ToA() c.F() ' output: A: doing F() c.G() ' output: A: doing G() c.ToB() c.F() ' output: B: doing F() c.G() ' output: B: doing G() Console.ReadLine() End Sub End Class Public Class A Implements I Public Sub F() Implements I.F System.Console.WriteLine("A: doing F()") End Sub Public Sub G() Implements I.G System.Console.WriteLine("A: doing G()") End Sub End Class Public Class B Implements I Public Sub F() Implements I.F System.Console.WriteLine("B: doing F()") End Sub Public Sub G() Implements I.G System.Console.WriteLine("B: doing G()") End Sub End Class Public Class C Implements I Private i As I Public Sub F() Implements I.F i.F() End Sub Public Sub G() Implements I.G i.G() End Sub Public Sub ToA() i = New A() End Sub Public Sub ToB() i = New B() End Sub End Class End Module
In this Delegation design pattern, an Interface is used instead. (If you're a bit rusty on Interfaces, try this article to explain how they work: Interface Definitions and Why You Should Care.
Click Here to display the illustration
The interface defines the two "tasks" that code can perform: the "F" task and the "G" task. Class "A" and Class "B" are two "roles" that use the implement the interface and define code to perform both tasks.
Since the definitions of Class "A" and Class "B" are where the tasks are coded, both roles perform both tasks, but the code could be completely different in each one. So, how the tasks are performed depends on how the tasks are coded in each class.
The final piece of the puzzle is Class "C". This class also implements the interface, but the function of Class C is to assign roles; that is, this is where the delegation happens. The variable naming is a bit confusing here. (Hey! That's what they used in Wikipedia for those other languages!)
Private i As I Public Sub F() Implements i.F i.F() End Sub
When task F is executed, the definition of that task that is instantiated as i is used. That code could use either the "A" or "B" role. To change roles, either ToA() or ToB() is executed:
Public Sub ToA() i = New A() End Sub
This changes the code instantiated as i (that is, changes the role that is the task is delegated to).
If you're like me, you find this stuff as clear as mud. Part 2 of this series introduces an example involving a small business with two employees (two roles). But to contrast the delegation design pattern, it's coded using inheritance instead.