Reputation: 19305
PHP and .Net have closures; I have been wondering what are some examples of using closures in OOP and design patterns, and what advantages they have over pure OOP programming.
As a clarification, this is not a OOP vs. functional programming, but how to best use closures in a OOP design. How do closures fit in, say, factories or the observer pattern? What are some tricks you can pull which clarify the design and results in looser coupling, for example.
Upvotes: 9
Views: 493
Reputation: 1797
Any language that has closures can use them for trampolining, which is a technique for refactoring recursion into iteration. This can get you out of "stack overflow" problems that naive implementations of many algorithms run into.
A trampoline is a function that "bounces" a closure back up to its caller. The closure captures "the rest of the work".
For example, in Python you can define a recursive accumulator to sum the values in an array:
testdata = range(0, 1000)
def accum(items):
if len(items) == 0:
return 0
elif len(items) == 1:
return items[0]
else:
return items[0] + accum(items[1:])
print "will blow up:", accum(testdata)
On my machine, this craps out with a stack overflow when the length of items exceeds 998.
The same function can be done in a trampoline style using closures:
def accum2(items):
bounced = trampoline(items, 0)
while (callable(bounced)):
bounced = bounced()
return bounced
def trampoline(items, initval):
if len(items) == 0:
return initval
else:
return lambda: trampoline(items[1:], initval+items[0])
By converting recursion to iteration, you don't blow out the stack. The closure has the property of capturing the state of the computation in itself rather than on the stack as you do with recursion.
Upvotes: 3
Reputation: 13684
Suppose you want to provide a class with the ability to create any number of FileOpener
instances, but following IoC principles, you don't want the class creating FileOpener
s to actually know how to do so (in other words, you don't want to new
them). Instead, you want to use dependency injection. However, you only want this class to be able to generate FileOpener
instances, and not just any instance. Here's what you can do:
class AppSetup
{
private IContainer BuildDiContainer()
{
// assume this builds a dependency injection container and registers the types you want to create
}
public void setup()
{
IContainer container = BuilDiContainer();
// create a function that uses the dependency injection container to create a `FileOpener` instance
Func<FileOpener> getFileOpener = () => { return container.Resolve<FileOpener>(); };
DependsOnFileOpener dofo = new DependsOnFileOpener(getFileOpener);
}
}
Now you have your class that needs to be able to make FileOpener instances. You can use dependency injection to provide it with this capability, while retaining loose coupling
class DependsOnFileOpener()
{
public DependesOnFileOpener(Func<FileOpener> getFileOpener)
{
// this class can create FileOpener instances any time it wants, without knowing where they come from
FileOpener f = getFileOpener();
}
}
Upvotes: 2
Reputation: 13684
Closures are useful for event-handling. This example is a bit contrived, but I think it conveys the idea:
class FileOpener
{
public FileOpener(OpenFileTrigger trigger)
{
trigger.FileOpenTriggered += (sender, args) => { this.Open(args.PathToFile); };
}
public void Open(string pathToFile)
{
//…
}
}
my file opener can either open a file by directly calling instance.Open(pathToFile)
, or it can be triggered by some event. If I didn't have anonymous functions + closures, I'd have to write a method that had no other purpose than to respond to this event.
Upvotes: 3