Sunday, December 31, 2006

The Initialize Pattern and the Open & Close Pattern


I have often been confronted with the "initialize" pattern or the "open and close" pattern. For instance there is some object that you instantiate but before you use it you must call an initialization method often like SomeClass.Initialize(). A similar pattern is that with objects that you need to open before usage and make sure that they are closed on usage completion. Often the situation can be handled using "acquisition is initialization". This works well with exceptions and stack unwinding. Sometimes the use of factories can meet the needs. I have a solution that is based on both and is a pattern that I have used when necessary.


In C# I use two classes an outer class and an inner class. The outer class's methods do not have public visibility, except for the constructor and a factory method. The inner class exposes the methods that can be performed on the outer class.


using System;
using System.Collections.Generic;
using System.Text;

namespace NestedTypes
{
public class CResource
{
public CResource()
{
}

protected void Open()
{
}

protected void Close()
{
}

protected void Read()
{
}

protected void Write()
{
}

public CResourceUser CreateUser()
{
return new CResourceUser(this);
}

public class CResourceUser : IDisposable
{
protected CResource resource;

internal CResourceUser(CResource resource)
{
this.resource = resource;
this.resource.Open();
}

public void Dispose()
{
this.resource.Close();
}

public void Read()
{
this.resource.Read();
}

public void Write()
{
this.resource.Write();
}
}
}
}



In this case I have the inner class implement the IDisposible interface which allows for the "using statement" in C#.


using System;
using System.Collections.Generic;
using System.Text;

namespace NestedTypes
{
class Program
{
static void Main(string[] args)
{
CResource resource = new CResource();
CResource.CResourceUser resourceUser = resource.CreateUser();
using (resourceUser)
{
resourceUser.Read();
resourceUser.Write();
}
}
}
}



I have used this pattern for implementing logging facilities. I have used this pattern in multi-threaded environments and I have found that this pattern made it obvious where synchronization must be handled.

No comments: