C# Design Patterns: #2 – The Factory Method

Factory MethodOne of the less useful C# design patterns is the Factory Method.  Primarily used for framework and toolkit development, this design pattern is rarely used in a language like C# that has templated classes, anonymous functions, interfaces, and reflection.

Factory methods are mainly used when developing a framework, or a set of functions, classes, and general infrastructure that will be used by other developers to create applications.  Since different applications will have different use cases, the applications developed using a particular framework may need to override the underlying classes and replace them with their own implementation.

For example, a framework called the SimpleDatabase framework might help developers create applications through Rapid Application Development.  The framework might have a set of classes that automatically generates the interface and database logic, based on a particular schema.  When developers implement this framework, they might occasionally need to implement custom database drivers for a particular database.  In this example, the framework handles creation of the database connections, and the developers need to subclass the framework to instantiate their custom database driver instead of the default driver:

public class Program{
  public static void Main(){
    SimpleDatabaseApp sda = new AccountingSystemApp();
    sda.CreateDBConnection();
  }
}
 
public class SimpleDatabaseApp {
  public virtual SimpleDBConnection CreateDBConnection(){ return new SimpleDBConnection(); }
}
 
public class SimpleDBConnection { /* Default database driver here */ }
 
public class AccountingSystemApp : SimpleDatabaseApp {
  public override SimpleDBConnection CreateDBConnection() { return new OracleDBConnection(); }
  /* Implements the rest of the accounting system here */
}
 
public class OracleDBConnection : SimpleDBConnection { /* Oracle database driver here */ }

In this example, the SimpleDatabase framework is used to create the AccountingSystemApp.  The OracleDBConnection will be used instead of the default SimpleDBConnection.  To make this happen, the AccountingSystemApp overrides the “factory method” called CreateDBConnection that actually instantiates the class, and this will instantiate the Oracle driver instead of the default driver.

When implementing this pattern, it’s very important to use the “override” keyword instead of the “new” keyword in the subclass.  The C# compiler will otherwise bind to the default factory method on the base class, instead of the new factory method.

The basic reason that the function “CreateDBConnection” is called a factory method is that it “manufactures” a new class.  While normally the class would be instantiated by the control loop, here instead the framework instantiates the class in the CreateDBConnection method.

Note: “Factory Method” refers to the actual function inside the class, not the class itself.

The reason factory methods aren’t popular in C# is that there are many excellent alternatives.  Templated classes are used heavily throughout the language, as in the implementation of IEnumerables such as Dictionary and List.  Alternatively, Reflection enables classes to create member variables based on a Type, instead of requiring the subclass to manually create the variable.  If all of these options were not enough, C# also supports anonymous functions, enabling dependency injection as opposed to factory methods.

Overall, the factory method design pattern is not particularly useful in the C# language, however it may help in the development of certain highly-customizable C# frameworks and toolkit packages.

Written by Andrew Palczewski

About the Author
Andrew Palczewski is CEO of apHarmony, a Chicago software development company. He holds a Master's degree in Computer Engineering from the University of Illinois at Urbana-Champaign and has over ten years' experience in managing development of software projects.
Google+

RSS Twitter LinkedIn Facebook Email

3 thoughts on “C# Design Patterns: #2 – The Factory Method”

  1. That first paragraph blows my mind, and not in a good way.

    Are you confusing factory methods with Service Location?

    The example you have provided does not reflect the factory pattern, nor the factory method pattern. In the nicest possible way, please check out some articles on these patterns, and perhaps modify/remove this article? It will confuse developers, and worse, could “teach” a junior developer some very incorrect principles regarding a common OO Patterns.

    For some more information, consider the following:
    Factory Pattern: http://www.oodesign.com/factory-pattern.html
    Factory Method Pattern: http://www.oodesign.com/factory-method-pattern.html

    1. คุณน้องแนะนำให้ใช้เวอร์ชั่นของ 4.5.9 นะค่ะ เพราะว่ายังคงการแปลภาษาแบบเดิมอยู่พี่ยังไม่ recommend เรื่องเวอร์ชั่นใหม่ให้ใช้กับ Live เพราะบางอย่างยังต้องอ้างอิงแบบเดิมนะจ๊ะ4.6.x มีการเปลี่ยนแปลงวิธีการ Translationถ้าไงลองดูวิธีใช้งานเรื่องภาษาที่เป็นแบบ XLIFF กับ exnestion เวอร์ชั่นใหม่ ๆ ดูค่ะ น่าจะช่วยได้ส่วนเรื่องของ register กับเวอร์ชั่น 4.6.x มีปัญหากับ div2007 ที่ยังไม่รองรับการแปลภาษาให้กับ register จ้าลองแก้ไขตามนี้จ้า (เทสให้พี่ด้วยนะ ได้ผลไงแจ้งด้วย)Path: sr_feuser_register/lib/class.tx_srfeuserregister_lang.php (บรรทัดประมาณ 120)function getLL ($key, $alt = , $hsc = FALSE) {// If the suffix is allowed and we have a localized string for the desired salutation, we’ll take that.$rc = ;if (isset($this->conf['salutation']) && in_array($this->conf['salutation'], $this->allowedSuffixes, 1)) {$expandedKey = $key.’_’.$this->conf['salutation'];$usedLang = ;//$rc = tx_div2007_alpha::getLL_fh001($this->pibase, $usedLang, $expandedKey, $alt, $hsc);$rc = $this->pibase->pi_getLL($expandedKey);}if ($rc == || $rc == $alt || $usedLang != $this->pibase->LLkey){//$rc = tx_div2007_alpha::getLL_fh001($this->pibase, $usedLang, $key, $alt, $hsc);$rc = $this->pibase->pi_getLL($key);}return $rc;}// getLLอย่าลืม save ตัวที่เราแก้ไข เก็บไว้ให้ดีหล่ะ จะได้ไม่ลืม ^^

Leave a Reply to Poetra Cancel reply

Your email address will not be published. Required fields are marked *