A heated discussion broke out at work today over the pros and cons of allowing the UI to reference the data access layer. I'm agnostic about this myself, but we have enforced this restriction and thus have a lot of pointless pass-thru methods that need to be maintained. Without discussing the merits of any of this, I was wondering, theoretically, how we could avoid writing pass-thru methods were we to use a more dynamic language.
Enter boo and its duck typing.
Say I have a TestRepository, and it has a method GetUser:
class TestRepository():
def constructor():
pass
def GetUser(name as string):
Console.WriteLine(name)
And I have my TestServices, that contains a TestRepository. I don't want to write the method on TestServices that just calls TestRepository, and maintain it an all of its parameters.
Instead, I can implement the interface IQuackFu, and implement its methods QuackInvoke, QuackSet and QuackGet
class TestServices(IQuackFu):
testRepository as TestRepository
def constructor(repository):
testRepository = repository
def QuackInvoke(name as string, args as (object)) as object:
# need to parse parameters to handle overloads
testRepository.GetType().GetMethod(name).Invoke(testRepository, args)
def QuackSet(name as string, parameters as (object), value) as object:
pass
def QuackGet(name as string, parameters as (object)) as object:
pass
Then if I have a service, declared as a duck (a valid type in boo), I can call any method on it and it will be handled by QuackInvoke.
[Test]
def can_call_child():
services as duck
services = TestServices(TestRepository())
services.GetUser("ignu")
services.GetUser("ignu") calls services.QuackInvoke("GetUser", "ignu") and our test passes:
Selected test: QuackTest.Test.can_call_child
ignu
Yay!
Len: 1 Compiler: 0
Actually, scratch that. This solution works... but it's not the most elegant solution in the universe. It's more of a draw.
We'll meet again, compiler. Mark my words.