Friday, February 16, 2007

Static Methods, Factories

What Is a Static Field or Method?

Let's change the question. When is a field or method not part of an object? Answer: when it is part of the class! Remember, an object is an instance of a class and each object exists in a separate space in memory. It is possible to access class fields and class methods without creating an instance of a class using the "static" key word. Declaring a field or method with the static key word, tells the compiler that the field or method is associated with the class itself, not with instances of the class. In a sense, static or "class" fields and methods are global variables and methods that you can touch using the class name. If you think of a class as a blueprint used to create objects, then you can think of static fields and methods are being part of the blueprint itself. There is only one copy of the static fields and methods in memory, shared by all instances of the class.

Static fields are useful when you want to store state related to all instances of a class. A counter is a good example of a static field. The classic use of a static counter is to generate a unique ID or serial number for each instance of a class.

Static methods are useful when you have behavior that is global to the class and not specific to an instance of a class. In contrast, instance methods are useful when the method needs to know about the state of an object. Since data and behavior are intertwined in an object, instance methods have access to the instance fields and can exhibit behavior that is specific to the state of an object.

Using Static Factory Methods Instead of Multiple Constructors


You might wonder why I have chosen to combine the topics of static methods and constructors into a single chapter. The answer is "static factory methods." Instead of writing multiple public constructors, you can write multiple static factory methods and private constructors that return objects. First, here is an example of a static factory method. The method simply constructs an object with default values and then returns a reference to the object.

public static Toaster GetInstance()
{
return new Toaster(ColorType.Black, DEFAULT_NAME);
}


In a sense, this static method is analogous to the no-arg constructor.

public Toaster() {}

Here is the version of the Toaster class that uses static methods and a single private constructor to return toaster objects:

///
/// Summary description for Toaster
///

class Toaster
{
// static factory methods
public static Toaster GetInstance()
{
return new Toaster(ColorType.Black, DEFAULT_NAME);
}
public static Toaster GetInstance(string modelName)
{
return new Toaster(ColorType.Black, modelName);
}
public static Toaster GetInstance(ColorType color)
{
return new Toaster(color, DEFAULT_NAME);
}
public static Toaster GetInstance(ColorType color, string modelName)
{
return new Toaster(color, modelName);
}
public const string DEFAULT_NAME= "Generic";
public enum ColorType {Black, Red, Yellow, White}; // black is the enum default value!
private static ColorType DEFAULT_COLOR= ColorType.Black;
private ColorType color= DEFAULT_COLOR;
private string modelName= DEFAULT_NAME;
// the single private constructor
private Toaster(ColorType color, string modelName)
{
this.color= color; // ColorType cannot be null --> compile time error or defaults to ColorType.Black!
if (modelName != null)
{
this.modelName= modelName;
}
}
// the getters
public string Color
{
get
{
return Enum.Format(typeof(ColorType), color,"G");
}
}
public string ModelName
{
get
{
return modelName; // danger, return ModelName --> stack overflow!
}
}
}

Declaring the only constructor private, prevents any outside caller from directly instantiating the class. The only path to a Toaster object is through a static factory method. So, you can use multiple overloaded public constructors or multiple static factory methods and private constructors to create toaster objects. If you are interested in learning more about using static factory methods instead of multiple constructers check out Effective Java Programming Language Guide by Joshua Bloch, Addison-Wessley, 2001, 252 pp.

Note: The behavior of enum is quite complicated. You cannot set an enum to null and if you fail to explicitly initialize an enum variable, it defaults to the first member of the enumeration. For example:

public static ColorType c; // c --> ColorType.Black


Creational Patterns -- Class Factory and Singleton

I am going to finish off this chapter by introducing two common design patterns: the "Class Factory" and "Singleton" patterns. The class factory is useful when you want to return concrete objects that share a base class, at runtime. The singleton pattern is useful when you only want to allow the creation of one instance of an object in a application. These patterns are both considered "Creational" patterns since they abstract the creation of objects.

Using a Static Method to Return Concrete Classes -- The Class Factory.

The concept of using static methods to return objects is a useful one. In the previous code, you learned how to replace multiple constructors with multiple static factory methods. Another useful design pattern is the "Class Factory." A class factory can be used to return concrete implementations of a common base type.

In Chapter 2, you learned about polymorphism using the Drawable abstract class. Concrete implementations of the Drawable class such as square or circle provide a concrete implementation of the abstract "DrawYourself" method. Let's resurrect our Drawable class.

abstract class Drawable
{
public abstract String DrawYourself();
}
class Circle : Drawable
{
public override String DrawYourself()
{
return "Circle";
}
}
class Square : Drawable
{
public override String DrawYourself()
{
return "Square";
}
}


In this example of the class factory pattern, you pass a parameter to a static factory method that then returns the appropriate concrete implementation of the Drawable abstract class. To insure that the method is passed valid parameters at compile time, you can define a type safe enum "DrawableType":

public enum DrawableType {CIRCLE,SQUARE};


Here is our class factory:

///
/// Summary description for class Factory.
///

class Factory
{
public enum DrawableType {CIRCLE,SQUARE};
public static Drawable GetInstance(DrawableEnum e)
{
if (e == DrawableType.CIRCLE)
{
return new Circle();
}
else if (e == DrawableType.SQUARE)
{
return new Square();
}
else
{
throw new IndexOutOfRangeException(); // should never get here
}
}
///
/// The main entry point for the application.
///

[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
Drawable d1= Factory.GetInstance(Factory.DrawableType.CIRCLE);
Console.WriteLine(d1.DrawYourself());
Drawable d2= Factory.GetInstance(Factory.DrawableType.SQUARE);
Console.WriteLine(d2.DrawYourself());Console.ReadLine();
}
}


Note that d1 and d1 are reference variables of the Type Drawable, yet the code outputs: Circle, Square. Polymorphism at work! The class factory design pattern allows your application to create concrete implementations of a base class or interface dynamically at runtime in response to user or system input.

The Singleton Pattern

The "Singleton" pattern is a special version of the class factory that only returns a single instance of a class. The singleton pattern is useful when there should only be one instance of an object. As an example, there may be many soldiers that derive from person, but there should only be one reigning King of England that derives from person! Here is a sample that uses a static factory method to insure that only one instance is created. The factory method "GetInstance" returns a reference to the single instance of the class. Note that you must declare any constructors private, so that the constructors are not visible outside of the class. This insures that. there will be one and only one instance of MyClass.

///
/// Summary description for MyClass.
///

class MyClass
{
private static MyClass theOnlyOne= new MyClass(); // create one and only one instance of the class
public static MyClass GetInstance()
{
return theOnlyOne;
}
public readonly string description= "The One and Only.";
private MyClass(){}
///
/// The main entry point for the application.
///

[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
MyClass mc= MyClass.GetInstance();
Console.WriteLine(mc.description);
Console.ReadLine();
}
}


One of the advantages of the factory method is that you can modify the singleton behavior of the class without affecting the caller of the class. If you decide that your application should now support Kings present and past, then you can modify MyClass to return a new instance for each call to GetInstance. Here is the modified multi-instance version of MyClass:

///
/// Summary description for MyClass
///

class MyClass
{
public static MyClass GetInstance()
{
return new MyClass();
}
public readonly string description= "OneOfMany";
///
/// The main entry point for the application.
///

[STAThread]
static void Main(string[] args)
{
//
// TODO: Add code to start application here
//
MyClass mc= MyClass.GetInstance();
Console.WriteLine(mc.description);
Console.ReadLine();
}
}