您的位置:首页 > 编程语言 > C#

无废话C#设计模式之三:Abstract Factory

2011-01-17 15:15 471 查看
无废话C#设计模式之三:Abstract Factory

意图

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

场景

还是上次说的那个网络游戏,定下来是一个休闲的FPS游戏。和CS差不多,8到16个玩家在游戏里面分成2组对战射击。现在要实现初始化场景的工作。要呈现一个三维物体一般两个元素是少不了的,一是这个物体的骨架,也就是模型,二就是这个骨架上填充的纹理。
我们知道,这样的一个游戏不可能只有一张地图,而且地图的数量肯定是会一直增加的。如果游戏在初始化场景的时候需要根据不同的地图分别加载模型和纹理对象,那么势必就会使得场景的扩充变得很不方便。由此,我们引入Abstract Factory,抽象工厂生产的都是实际类型的接口(或者抽象类型),如果加了新的场景可以确保不需要修改加载场景的那部分代码。

示例代码

using System;

using System.Reflection;

namespace AbstractFactoryExample
{
classProgram
{
staticvoid Main(string[] args)
{
Patrix patrix = newPatrix();
patrix.LoadScene("HalfPaper");
patrix.LoadScene("Matrix");
}
}

classPatrix
{
privatePatrixSceneFactory GetGameScene(string gameSceneName)
{
return (PatrixSceneFactory)Assembly.Load("AbstractFactoryExample").CreateInstance("AbstractFactoryExample." + gameSceneName);
}

publicvoid LoadScene(string gameSceneName)
{
PatrixSceneFactory psf = GetGameScene(gameSceneName);
Texture texture = psf.CreateTexture();
Model model = psf.CreateModel();
model.FillTexture(texture);
}
}

abstractclassPatrixSceneFactory
{
publicabstractModel CreateModel();

publicabstractTexture CreateTexture();
}

abstractclassModel
{
publicabstractvoid FillTexture(Texture texture);
}

abstractclassTexture
{

}

classHalfPaper : PatrixSceneFactory
{
publicoverrideModel CreateModel()
{
returnnewHalfPaperModel();
}

publicoverrideTexture CreateTexture()
{
returnnewHalfPaperTexture();
}
}

classHalfPaperModel : Model
{
public HalfPaperModel()
{
Console.WriteLine("HalfPaper Model Created");
}

publicoverridevoid FillTexture(Texture texture)
{
Console.WriteLine("HalfPaper Model is filled Texture");
}
}

classHalfPaperTexture : Texture
{
public HalfPaperTexture()
{
Console.WriteLine("HalfPaper Texture Created");
}
}

classMatrix : PatrixSceneFactory
{
publicoverrideModel CreateModel()
{
returnnewMatrixModel();
}

publicoverrideTexture CreateTexture()
{
returnnewMatrixTexture();
}
}

classMatrixModel : Model
{
public MatrixModel()
{
Console.WriteLine("Matrix Model Created");
}

publicoverridevoid FillTexture(Texture texture)
{
Console.WriteLine("Matrix Model is filled Texture");
}
}

classMatrixTexture : Texture
{
public MatrixTexture()
{
Console.WriteLine("Matrix Texture Created");
}
}
}
代码执行结果如下图:

代码说明

l PatrixSceneFactory就是一个抽象工厂,它声明了创建抽象的场景以及抽象的纹理的接口。(广告时间:Patrix是我公司的一款休闲FPS游戏,详细请见http://www.qwd1.com
l Model和Texture是抽象产品。在Model类中有一个抽象方法,用于为模型填充纹理。
l HalfPaper和Matrix是具体工厂,它用于创建某个场景的模型和纹理。(你可能对两个类的名字不太理解,其实HalfPaper和Matrix是两个地图的名字)
l xxxModel和xxxTexture就是具体的产品了。它们就是针对某个场景的模型和纹理,具体工厂负责创建它们。
l Patrix这个类负责加载场景,为了避免加载不同场景使用case语句,在这里我们使用反射来加载具体工厂类。
l 可以看到,一旦有了新的场景(或者说地图),我们只需要设计新的xxxModel和xxxTexture以及具体工厂类就可以了,加载场景的那部分代码(也就是Patrix类)不需要做改动。
l 我们现在这个游戏可是不支持和电脑对战的,万一以后需要支持电脑了,那么场景中的元素除了纹理和模型之外就还需要加电脑了。也就是说抽象工厂还需要多生产一种类型的产品,这个时候抽象工厂就无能为力了。抽象工厂只能解决系列产品扩张的变化点(在我们的例子中就是地图的新增),因此千万把抽象工厂所能生产的产品考虑周全了。

何时采用

l 从代码角度来说,你希望在统一的地方创建一系列相互关联的对象,并且基于抽象对象的时候。
l 从应用角度来说,如果你的产品是成组成套的,并且肯定会不断扩展新系列的,那么就适用抽象工厂。比如说,外面买的塑料模型,里面总是有图纸、模型元件板和外壳包装三部分。那么生产模型的厂就是抽象工厂,打印图纸、打印包装盒以及生产元件板的三个流水线就是具体工厂了。需要生产新的模型,只需要制作新的图纸输入到三个流水线的电脑中就可以了。

实现要点

l 抽象工厂本身不负责创建产品,产品最终还是由具体工厂来创建的。比如,MatrixModel是Matrix创建的,而不是PatrixSceneFactory创建的。在.NET中可以使用反射来创建具体工厂,从而使得代码变动降到最低。
l 在抽象工厂中需要体现出生产一系列产品。这一系列产品是相互关联,相互依赖一起使用的。
l 抽象工厂对应抽象产品,具体工厂对应具体产品,外部依赖抽象类型,这样对于新系列产品的创建,外部唯一依赖的就是具体工厂的创建过程(可以通过反射解决)。

注意事项

l 一般来说需要创建一系列对象的时候才考虑抽象工厂。比如,创建一个场景,需要创建模型和纹理,并且模型和纹理之间是有一定联系的,不太可能把PatrixTexture套用在MatrixModel上。
l 如果系统的变化点不在新系列的扩充上,那么就没有必要使用抽象工厂。比如,如果我们不会增加新地图的话,那么也就没有必要引入抽象工厂。

.NET中的抽象工厂

l 我们说过,抽象工厂针对系列产品的应变。在使用ADO.NET进行数据访问的时候,如果目标数据库是Access,我们会使用OleDbConnection、OleDbCommand以及OleDbDataAdapter等一系列ADO.NET对象。那么如果数据库是SQL Server,我们又会改用SqlConnection、SqlCommand以及SqlDataAdapter等一系列ADO.NET对象。如果只使用一套对象,没有什么大问题,如果我们的数据访问有系列变化的需求,比如可以针对Access和SQL Server,而且希望改换数据库尽量对客户端代码透明,那么就需要引入抽象工厂模式。
l 好在,ADO.NET 2.0中已经有了整套抽象工厂的类型。看下面的代码,你应该能辨别这些类型在抽象工厂中的角色:

publicabstractclassDbProviderFactory

{
// Methods
protected DbProviderFactory()
{
}

publicvirtual DbCommand CreateCommand()
{
returnnull;
}

publicvirtual DbCommandBuilder CreateCommandBuilder()
{
returnnull;
}

publicvirtual DbConnection CreateConnection()
{
returnnull;
}

publicvirtual DbConnectionStringBuilder CreateConnectionStringBuilder()
{
returnnull;
}

publicvirtual DbDataAdapter CreateDataAdapter()
{
returnnull;
}

publicvirtual DbDataSourceEnumerator CreateDataSourceEnumerator()
{
returnnull;
}

publicvirtual DbParameter CreateParameter()
{
returnnull;
}

publicvirtual CodeAccessPermission CreatePermission(PermissionState state)
{
returnnull;
}

// Properties
publicvirtualbool CanCreateDataSourceEnumerator
{
get
{
returnfalse;
}
}
}

publicsealedclassOleDbFactory : DbProviderFactory
{
// Fields
publicstaticreadonlyOleDbFactory Instance = newOleDbFactory();

// Methods
private OleDbFactory()
{
}

publicoverride DbCommand CreateCommand()
{
returnnewOleDbCommand();
}

publicoverride DbCommandBuilder CreateCommandBuilder()
{
returnnewOleDbCommandBuilder();
}

publicoverride DbConnection CreateConnection()
{
returnnewOleDbConnection();
}

publicoverride DbConnectionStringBuilder CreateConnectionStringBuilder()
{
returnnewOleDbConnectionStringBuilder();
}

publicoverride DbDataAdapter CreateDataAdapter()
{
returnnewOleDbDataAdapter();
}

publicoverride DbParameter CreateParameter()
{
returnnewOleDbParameter();
}

publicoverride CodeAccessPermission CreatePermission(PermissionState state)
{
returnnewOleDbPermission(state);
}
}

publicsealedclassSqlClientFactory : DbProviderFactory, IServiceProvider
{
// Fields
publicstaticreadonlySqlClientFactory Instance = newSqlClientFactory();

// Methods
private SqlClientFactory()
{
}

publicoverride DbCommand CreateCommand()
{
returnnewSqlCommand();
}

publicoverride DbCommandBuilder CreateCommandBuilder()
{
returnnewSqlCommandBuilder();
}

publicoverride DbConnection CreateConnection()
{
returnnewSqlConnection();
}

publicoverride DbConnectionStringBuilder CreateConnectionStringBuilder()
{
returnnewSqlConnectionStringBuilder();
}

publicoverride DbDataAdapter CreateDataAdapter()
{
returnnewSqlDataAdapter();
}

publicoverride DbDataSourceEnumerator CreateDataSourceEnumerator()
{
return SqlDataSourceEnumerator.Instance;
}

publicoverride DbParameter CreateParameter()
{
returnnewSqlParameter();
}

publicoverride CodeAccessPermission CreatePermission(PermissionState state)
{
returnnewSqlClientPermission(state);
}

objectIServiceProvider.GetService(Type serviceType)
{
object obj2 = null;
if (serviceType == GreenMethods.SystemDataCommonDbProviderServices_Type)
{
obj2 = GreenMethods.SystemDataSqlClientSqlProviderServices_Instance();
}
return obj2;
}

// Properties
publicoverridebool CanCreateDataSourceEnumerator
{
get
{
returntrue;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: