对象创建是面向对象程度的最常见活动之一。对象的创建通常有两种方式:直接创建,或者是间接创建。
直接创建对象
直接创建意味着由使用对象的元素直接创建对象,然后使用对象。这种方式最常用,也是对象之间建立耦合的最常见方式,也是如非必要,优先考虑的对象创建方式。例如下面的C#代码:
public class ComponentA { // 类的成员直接new出来 ComponentB m_componentB = new ComponentB(); public ComponentA() { } public void Action() { m_componentB.Say(); } static void Main(string[] args) { // 函数的本地变量直接new出来 ComponentA component = new ComponentA(); component.Action(); } } class ComponentB { public void Say() { Console.WriteLine("Hello!"); } }
间接创建对象
间接创建意味着由专门的元素来创建对象,然后返回给响应的元素来使用。这些专门用于创建对象的元素我们称之为"工厂",按照创建的方式的不同,变化情况的不同,对于扩展的要求不同,有下面一些工厂:
工厂函数
对于一些创建时需提供各种不同参数的产品,我们可以简单使用重载函数来封装产品的创建过程。这种方式是使用函数这种最简单的封装方式封装了可能存在变化的对象创建细节(此刻请在心里多默念几遍“封装变化”)。这种方式对于产品不存在复杂的继承情况的场合,使用起来效果还是不错的。
注意观察下面例子中的几个static函数:
public class Program { static void Main(string[] args) { Component componentA = Component.makeEmptyComponent(); Component componentB = Component.makeSimpleComponent("Test"); componentA.Say(); componentB.Say(); } } public class Component { private string m_name; private Component (string name, int id, string summary, string description, int priority) { m_name = name; } public void Say() { Console.WriteLine("Hi, my name is {0}", m_name); } public static Component makeEmptyComponent() { return new Component("Empty", 0, "", "", 0); } public static Component makeSimpleComponent(string name) { return new Component(name, 0, "", "", 0); } public static Component makeNormalComponent(string name, int id, string summary) { return new Component(name, id, summary, "", 0); } }
使用一个简单的工厂对象提供创建各种产品对象的方法,使用起来可以很好的隔离对象的创建细节。这种方式把可能复杂多变的创建过程从原对象中剥离,然后放到单独的类中封装起来。它不属于GoF设计模式的一种,但是由于简单易用,也是一种不错的代码组织方式。
注意下面例子中的static类和其static方法:
public class Program { static void Main(string[] args) { Component componentA = SimpleFactory.makeComponentA(); Component componentB = SimpleFactory.makeComponentB(); componentA.M(); componentB.M(); } } public static class SimpleFactory { public static Component makeComponentA() { return new ComponentA(); } public static Component makeComponentB() { return new ComponentB(); } } public class Component { public virtual void M() { } } public class ComponentA : Component { public override void M() { Console.WriteLine("This is A"); } } public class ComponentB : Component { public override void M() { Console.WriteLine("This is B"); } }
工厂方法
使用工厂对象封装产品对象的创建过程,通常由子类完成具体产品对象的创建过程。这种方式使用了多态去封装和表达变化,从而达到封装对象创建细节的目的。
注意例子中的abstract工厂的使用:
public class Program { static void Main(string[] args) { ComponentAFactory componentAFactory = new ComponentAFactory(); Component componentA = componentAFactory.makeComponent(); componentA.M(); } } public abstract class Factory { public abstract Component makeComponent(); } public class ComponentAFactory : Factory { public override Component makeComponent() { return new ComponentA(); } } public class ComponentBFactory : Factory { public override Component makeComponent() { return new ComponentB(); } }
抽象工厂
使用工厂对象封装产品族的创建过程,通常由子类完成具体产品族的创建过程,基本上是工厂方法的组合用法。
抽象工厂其实是在工厂方法的基础上,增加了多个产品的创建,也就是工厂类多几个抽象方法,用于创建不同类别的产品,简单看一下:
public abstract class CarFactory { public abstract Wheel makeWheel(); public abstract Light makeLight(); }
工厂子类去实现创建产品的细节,是不是本质上与工厂方法没什么区别?