Design Patterns in memory managed languages

11th August 2010

A lot of the work I am currently doing revolves around a legacy Delphi codebase. Delphi is an objected oriented language based on the Pascal syntax - and it requires the programmer to manage memory. As such, it has been an interesting challenge to attempt to apply modern design patterns to such a codebase. Languages such as Java and Ruby don’t require the programmer to free up objects after they are no longer required, and as such many of the patterns we use in these languages need to be modified in order to apply them in a language such as Delphi.

For example, the following is a common pattern in constructor overloading:

class Foo {
field Bar bar;

constructor Foo() {
this(new DefaultBar());

constructor Foo(Bar bar) { = bar;

Constructor overloading in this manner allows the user to inject custom behaviour if desired, or make use of a default implementation. However, in a memory managed language, what should the destructor do? If bar was initialised using the first constructor, then Foo, is responsible for the clean up of bar. However, if bar was injected, then traditionally, the calling method is responsible for the clean up of bar. One option is getting Foo to remember whether bar was initialised or injected. However this is messy and obscures business logic occurring in Foo. Another alternative always make Foo responsible for the clean up of bar. This fits nicely with another pattern than needs to be adapted for a memory managed language - the Factory pattern.

class FooFactory {
Foo createFoo() {
Bar bar = new MarsBar();
return new Foo(bar);

In this case, FooFactory cannot be responsible for the destruction of Foo. Instead, that responsibility becomes that of the method which called FooFactory. Also, Foo becomes responsible for the destruction of bar as well.

Therefore, to properly make use of dependency injection in memory managed languages, certain concepts must be challenged. The method that creates an object is no longer its clear owner. When applying dependency injection in languages such as this, it is more important than ever to use sensible domain objects and abstractions. This makes it clear who owns any given object, and therefore who is responsible for its destruction.

blog comments powered by Disqus