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

转载 2011年01月17日 15:15:00

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

 

意图

 

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

 

场景

 

       还是上次说的那个网络游戏,定下来是一个休闲的FPS游戏。和CS差不多,816个玩家在游戏里面分成2组对战射击。现在要实现初始化场景的工作。要呈现一个三维物体一般两个元素是少不了的,一是这个物体的骨架,也就是模型,二就是这个骨架上填充的纹理。

       我们知道,这样的一个游戏不可能只有一张地图,而且地图的数量肯定是会一直增加的。如果游戏在初始化场景的时候需要根据不同的地图分别加载模型和纹理对象,那么势必就会使得场景的扩充变得很不方便。由此,我们引入Abstract Factory,抽象工厂生产的都是实际类型的接口(或者抽象类型),如果加了新的场景可以确保不需要修改加载场景的那部分代码。

 

示例代码

 

using System;

using System.Reflection;

 

namespace AbstractFactoryExample

{

    class Program

    {

        static void Main(string[] args)

        {

            Patrix patrix = new Patrix();

            patrix.LoadScene("HalfPaper");

            patrix.LoadScene("Matrix");

        }

    }

 

    class Patrix

    {

        private PatrixSceneFactory GetGameScene(string gameSceneName)

        {

            return (PatrixSceneFactory)Assembly.Load("AbstractFactoryExample").CreateInstance("AbstractFactoryExample." + gameSceneName);

        }

 

        public void LoadScene(string gameSceneName)

        {

            PatrixSceneFactory psf = GetGameScene(gameSceneName);

            Texture texture = psf.CreateTexture();

            Model model = psf.CreateModel();

            model.FillTexture(texture);

        }

    }

 

    abstract class PatrixSceneFactory

    {

        public abstract Model CreateModel();

 

        public abstract Texture CreateTexture();

    }

 

    abstract class Model

    {

        public abstract void FillTexture(Texture texture);

    }

 

    abstract class Texture

    {

 

    }

 

    class HalfPaper : PatrixSceneFactory

    {

        public override Model CreateModel()

        {

            return new HalfPaperModel();

        }

 

        public override Texture CreateTexture()

        {

            return new HalfPaperTexture();

        }

    }

 

    class HalfPaperModel : Model

    {

        public HalfPaperModel()

        {

            Console.WriteLine("HalfPaper Model Created");

        }

 

        public override void FillTexture(Texture texture)

        {

            Console.WriteLine("HalfPaper Model is filled Texture");

        }

    }

 

    class HalfPaperTexture : Texture

    {

        public HalfPaperTexture()

        {

            Console.WriteLine("HalfPaper Texture Created");

        }

    }

 

    class Matrix : PatrixSceneFactory

    {

        public override Model CreateModel()

        {

            return new MatrixModel();

        }

 

        public override Texture CreateTexture()

        {

            return new MatrixTexture();

        }

    }

 

    class MatrixModel : Model

    {

        public MatrixModel()

        {

            Console.WriteLine("Matrix Model Created");

        }

 

        public override void FillTexture(Texture texture)

        {

            Console.WriteLine("Matrix Model is filled Texture");

        }

    }

 

    class MatrixTexture : Texture

    {

        public MatrixTexture()

        {

            Console.WriteLine("Matrix Texture Created");

        }

    }

}

代码执行结果如下图:

 

 

代码说明

 

l         PatrixSceneFactory就是一个抽象工厂,它声明了创建抽象的场景以及抽象的纹理的接口。(广告时间:Patrix是我公司的一款休闲FPS游戏,详细请见http://www.qwd1.com

l         ModelTexture是抽象产品。在Model类中有一个抽象方法,用于为模型填充纹理。

l         HalfPaperMatrix是具体工厂,它用于创建某个场景的模型和纹理。(你可能对两个类的名字不太理解,其实HalfPaperMatrix是两个地图的名字)

l         xxxModelxxxTexture就是具体的产品了。它们就是针对某个场景的模型和纹理,具体工厂负责创建它们。

l         Patrix这个类负责加载场景,为了避免加载不同场景使用case语句,在这里我们使用反射来加载具体工厂类。

l         可以看到,一旦有了新的场景(或者说地图),我们只需要设计新的xxxModelxxxTexture以及具体工厂类就可以了,加载场景的那部分代码(也就是Patrix类)不需要做改动。

l         我们现在这个游戏可是不支持和电脑对战的,万一以后需要支持电脑了,那么场景中的元素除了纹理和模型之外就还需要加电脑了。也就是说抽象工厂还需要多生产一种类型的产品,这个时候抽象工厂就无能为力了。抽象工厂只能解决系列产品扩张的变化点(在我们的例子中就是地图的新增),因此千万把抽象工厂所能生产的产品考虑周全了。

 

何时采用

 

l         从代码角度来说,你希望在统一的地方创建一系列相互关联的对象,并且基于抽象对象的时候。

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

 

实现要点

 

l         抽象工厂本身不负责创建产品,产品最终还是由具体工厂来创建的。比如,MatrixModelMatrix创建的,而不是PatrixSceneFactory创建的。在.NET中可以使用反射来创建具体工厂,从而使得代码变动降到最低。

l         在抽象工厂中需要体现出生产一系列产品。这一系列产品是相互关联,相互依赖一起使用的。

l         抽象工厂对应抽象产品,具体工厂对应具体产品,外部依赖抽象类型,这样对于新系列产品的创建,外部唯一依赖的就是具体工厂的创建过程(可以通过反射解决)。

 

注意事项

 

l         一般来说需要创建一系列对象的时候才考虑抽象工厂。比如,创建一个场景,需要创建模型和纹理,并且模型和纹理之间是有一定联系的,不太可能把PatrixTexture套用在MatrixModel上。

l         如果系统的变化点不在新系列的扩充上,那么就没有必要使用抽象工厂。比如,如果我们不会增加新地图的话,那么也就没有必要引入抽象工厂。

 

.NET中的抽象工厂

 

l         我们说过,抽象工厂针对系列产品的应变。在使用ADO.NET进行数据访问的时候,如果目标数据库是Access,我们会使用OleDbConnectionOleDbCommand以及OleDbDataAdapter等一系列ADO.NET对象。那么如果数据库是SQL Server,我们又会改用SqlConnectionSqlCommand以及SqlDataAdapter等一系列ADO.NET对象。如果只使用一套对象,没有什么大问题,如果我们的数据访问有系列变化的需求,比如可以针对AccessSQL Server,而且希望改换数据库尽量对客户端代码透明,那么就需要引入抽象工厂模式。

l         好在,ADO.NET 2.0中已经有了整套抽象工厂的类型。看下面的代码,你应该能辨别这些类型在抽象工厂中的角色:

    public abstract class DbProviderFactory

    {

        // Methods

        protected DbProviderFactory()

        {

        }

 

        public virtual DbCommand CreateCommand()

        {

            return null;

        }

 

        public virtual DbCommandBuilder CreateCommandBuilder()

        {

            return null;

        }

 

        public virtual DbConnection CreateConnection()

        {

            return null;

        }

 

        public virtual DbConnectionStringBuilder CreateConnectionStringBuilder()

        {

            return null;

        }

 

        public virtual DbDataAdapter CreateDataAdapter()

        {

            return null;

        }

 

        public virtual DbDataSourceEnumerator CreateDataSourceEnumerator()

        {

            return null;

        }

 

        public virtual DbParameter CreateParameter()

        {

            return null;

        }

 

        public virtual CodeAccessPermission CreatePermission(PermissionState state)

        {

            return null;

        }

 

        // Properties

        public virtual bool CanCreateDataSourceEnumerator

        {

            get

            {

                return false;

            }

        }

    }

 

    public sealed class OleDbFactory : DbProviderFactory

    {

        // Fields

        public static readonly OleDbFactory Instance = new OleDbFactory();

 

        // Methods

        private OleDbFactory()

        {

        }

 

        public override DbCommand CreateCommand()

        {

            return new OleDbCommand();

        }

 

        public override DbCommandBuilder CreateCommandBuilder()

        {

            return new OleDbCommandBuilder();

        }

 

        public override DbConnection CreateConnection()

        {

            return new OleDbConnection();

        }

 

        public override DbConnectionStringBuilder CreateConnectionStringBuilder()

        {

            return new OleDbConnectionStringBuilder();

        }

 

        public override DbDataAdapter CreateDataAdapter()

        {

            return new OleDbDataAdapter();

        }

 

        public override DbParameter CreateParameter()

        {

            return new OleDbParameter();

        }

 

        public override CodeAccessPermission CreatePermission(PermissionState state)

        {

            return new OleDbPermission(state);

        }

    }

 

    public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider

    {

        // Fields

        public static readonly SqlClientFactory Instance = new SqlClientFactory();

 

        // Methods

        private SqlClientFactory()

        {

        }

 

        public override DbCommand CreateCommand()

        {

            return new SqlCommand();

        }

 

        public override DbCommandBuilder CreateCommandBuilder()

        {

            return new SqlCommandBuilder();

        }

 

        public override DbConnection CreateConnection()

        {

            return new SqlConnection();

        }

 

        public override DbConnectionStringBuilder CreateConnectionStringBuilder()

        {

            return new SqlConnectionStringBuilder();

        }

 

        public override DbDataAdapter CreateDataAdapter()

        {

            return new SqlDataAdapter();

        }

 

        public override DbDataSourceEnumerator CreateDataSourceEnumerator()

        {

            return SqlDataSourceEnumerator.Instance;

        }

 

        public override DbParameter CreateParameter()

        {

            return new SqlParameter();

        }

 

        public override CodeAccessPermission CreatePermission(PermissionState state)

        {

            return new SqlClientPermission(state);

        }

 

        object IServiceProvider.GetService(Type serviceType)

        {

            object obj2 = null;

            if (serviceType == GreenMethods.SystemDataCommonDbProviderServices_Type)

            {

                obj2 = GreenMethods.SystemDataSqlClientSqlProviderServices_Instance();

            }

            return obj2;

        }

 

        // Properties

        public override bool CanCreateDataSourceEnumerator

        {

            get

            {

                return true;

            }

        }

}

 

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

意图        提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 场景        还是上次说的那个网络游戏,定下来是一个休闲的FPS游戏。和CS差不多,8到16个玩家在游戏...
  • wangyjyj
  • wangyjyj
  • 2007年10月19日 16:58
  • 303

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

本系列文章将向大家介绍一下C#的设计模式,此为第三篇文章,相信对大家会有所帮助的。废话不多说,继续来看。  意图  提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。  场景  还是...
  • mydriverc
  • mydriverc
  • 2008年03月07日 15:54
  • 510

设计模式——抽象工厂模式(Abstract Factory)

要想正确的理解设计模式,首先必须明确它是为了解决什么问题而提出来的。 抽象设计模式概念:         针对抽象工厂这个设计模式,我查找了不少资料,感觉只有涉及产品级别和产品族的才是理解了抽象工厂设...
  • u012909091
  • u012909091
  • 2014年08月02日 16:52
  • 3607

深入浅出设计模式 ------ Abstract Factory(抽象工厂)

本文可以和笔者的深入浅出设计模式 ------ Factory Method(工厂方法)参照着看, 可以区分这三个工厂模式的不同。...
  • wenniuwuren
  • wenniuwuren
  • 2015年01月29日 02:25
  • 1729

设计模式:Abstract Factory和Builder(比较区别,个人认为讲得很明白)

如果说 Factory和Prototype是同一个层次的话,那么Abstract Factory和Builder就是更高一级的层次。 1 Abstact Factory   在上面的Factory类型...
  • lovingprince
  • lovingprince
  • 2007年04月17日 10:59
  • 4231

无废话MVC系列教程

http://www.cnblogs.com/iamlilinfeng/category/454097.html MVC入门教程 摘要: 一、前言以下是我自己写的MVC入门教程和一个外...
  • SalmonellaVaccine
  • SalmonellaVaccine
  • 2014年05月24日 02:24
  • 1161

【java设计模式】之 抽象工厂(Abstract Factory)模式

1. 女娲的失误         上一节学习了工厂模式,女娲运用了该模式成功创建了三个人种,可是问题来了,她发现没有性别……这失误也忒大了点吧……竟然没有性别,那岂不是……无奈,只好抹掉重来了,于是所...
  • eson_15
  • eson_15
  • 2016年04月26日 23:49
  • 11663

设计模式之三 抽象工厂模式 Abstract Factory

一、模式定义 提供一个创建一系列相关或相互依赖对象的接口,并无需指定它们具体的类。...
  • icanhaha
  • icanhaha
  • 2015年11月27日 17:25
  • 143

Factory Method vs Abstract Factory

Factory Method vs Abstract Factory
  • u010373266
  • u010373266
  • 2016年12月20日 16:26
  • 318

设计模式之——设计模式使用率排行榜

Java设计模式使用率爬行榜 使用频率 所属类型 模式名称 模式 简单定义 5 创建型 Singleton 单例模式 保证一个类只有一个实例,并提供一个访问它的...
  • wind19
  • wind19
  • 2011年11月15日 14:29
  • 1173
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:无废话C#设计模式之三:Abstract Factory
举报原因:
原因补充:

(最多只允许输入30个字)