You can easily research how to use a delegate, but most of the materials out there don’t really tell you the use-cases of these delegates, and so you don’t tend to use it. They give you a Hello-World-like example and you’re left to figure out how, when and why you’d implement it on your applications. In this blog, we’ll use delegate to build a flexible, dynamic and extendable password validation business rule.
But before that, some short discussion on delegates…
To me, a delegate is a form of abstraction without using a class or interface, but simply using regular subroutines and/or functions. Abstraction allows you to write dynamic behaviors in your application and extend it beyond its initial purpose.
Analogy
Think of abstraction as a USB port on a computer. USB port allows you to attach a mouse, keyboard, external disk and even cell phones. Different objects, yet all using the same interface (the USB).
Key Points when using Delegates
These are the major points you need to ensure when writing delegates and implementing them:
- The method type must be the same (SUB or FUNCTION). You implement a SUB-routine if the delegate is a subroutine, etc.
- The signature must be the same and in the correct order. Think of signature as the sequence of parameter declarations of a sub or function. If the delegate has 3 parameters (string, integer, boolean) then you should have a similar parameter list.
- The return type must be the same (if you’re using a function)
Coding
Super Simple Example
Here’s a very simple introductory code for a delegate and a concrete implementation:
The delegate validation_delegate is a SUB-routine delegate with one parameter of type string.
We then implement similar routine (password_cannot_be_blank) with the same signature so we can use it correctly.
To use this:
- We create a variable (validate_password) with a data type that is the delegate (validation_delegate)
- We assign the concrete implementation (password_cannot_be_blank) to this variable using the “address of” keyword
- We call or invoke this variable (validate_password) and pass the parameter (strPassword) to it.
Fail Test
If we run this code now (without setting a value for the password), this is what we’ll get (as expected):
Pass Test
When we set the password to a non-blank value, the validation will succeed (as expected_:
Expanded Example
Now that you’ve deployed that code, the Security Council wants you to add more validation to your application.
Aren’t you glad you used delegates instead of hardcoding it like most programmers do? 🙂
Password Validation Suite
Since your first code is already working, you don’t want to touch it, so instead you created a class to contain all the validation rules that the Security Council wants you to implement. They initially gave you two (2) validation rules to implement:
- Password must have a number
- Password must contain a special character
With that, you wrote the class like this:
Password Must Have a Number
Very simply, you defined the business rule to check if the password contains a number. If it doesn’t, then we simply raise an exception.
Password Must Contain a Special Character
You’re on a roll and proceeded to code the validation to ensure at least one special character is found on the password:
Put in on a list
(but in my head it sounds like Puttin’ on a ritz)
Since we want future validation routines to be easy to add, it’s a sign to refactor the original code. We’re going to create a List of validation_delegate and then populate it with all the validation rules the Security Council wants.
And now our code looks like this:
Performing all the validation rules
Now that every validation logic is on a list, it’s super simple to call them one by one. We just iterate over that list, and we invoke each item (inside a Try..Catch block) to perform them.
Notice also that we collect the validation errors first and then we display them (if any).
Baseline Test
Not changing the previous password, let’s run it and see if the 2 new validation rules failed:
Passing the 2nd validation rule
Adding a number to our password
Now, let us change the letter “e” to a number “3” to pass one of the new validation logic:
Passing the 3rd validation rule
Adding a special character to our password
Lastly, we change the character “a” into the special character “at” sign (@) to pass the 3rd validation rule:
Using a Wrapper
To properly illustrate “injection”
Of course, if we just put the implementations on the list then it’s hard to see the “injection” part of this blog. 🙂
It was intentional, so you can see first how it’s being done and so when I introduce a wrapper routine, it’d be easier to understand.
Perform Validation: Wrapper
This routine takes in two (2) arguments:
- The implementation of the delegate
- The parameter to pass to the delegate (in this case, the password string)
The Injection Portion
This routine “depends” on a delegate implementation, and so we have to “inject” an implementation of the delegate to make this work. The conversion is quite easy: we just call this routine and pass the implementation (instead of [originally] calling it directly).
I kept the original line (commented) for comparison.
Conclusion
Abstraction is a great tool for making your application dynamic and allows you to extend it beyond its initial functionality. As long as you follow the guides in using delegates, you’ll find that most of your old codes probably would benefit from using abstractions.
Other use-cases that you can use abstractions (via delegates or other):
Implementing a search engine.
You can write a search_delegate and then implement various search engines. Most browsers do this nowadays, where you can tell it which search engine you want to use when searching from the URL bar.
Implementing an export data abstraction layer
You can write an export_data_delegate and implement various export methods per file format (for example). export_to_csv, export_to_pdf, export_to_html, etc.
My Preferred Abstraction Technique
Delegate is my preferred abstraction technique because it doesn’t force the implementing code to write a class.
Abstraction using Interface or base classes forces you to create a class, even if for a simple task.
Notice also that delegates is not limited to normal subroutines or functions, it works even on class methods (as we’ve seen in the Password Validation Suite class). So, definitely consider delegate first when you need abstraction. Only resort to class-based abstractions when it makes more sense to (justifiably) do so.
Source Codes
If you want to try this out, the source codes are in my Git Hub page below: