简单工厂设计模式例子,工厂方法模式实例

  简单工厂设计模式例子,工厂方法模式实例

  工厂的概念在面向对象编程中反复出现,在C#本身和其他设计模式(如生成器模式)中都可以找到几个例子。在这个例子中,有一个类决定在单继承架构中实例化哪个单词类。

  工厂方法模式是这一思想的巧妙扩展。superclass没有使用一个特殊的类来决定实例化哪个单词类,而是延迟了这个决定。

  没有子类。这种设计模式其实是没有决策点的,也就是没有直接选择一个词类进行实例化的决策。根据这种模式编写的程序定义了一个抽象类,它创建对象,

  但是让子类决定创建哪种对象。

  这里,考虑一个在游泳比赛中为运动员确定泳道的相当简单的例子。在一项赛事中,游泳运动员完成若干次预赛后,按照从前一次预赛最慢到最后一次预赛最快的顺序,

  对运动员成绩进行排名,下次比赛安排最快的游泳运动员在中间泳道。这种确定车道的方式称为直接排序。

  目前,游泳运动员在参加锦标赛时通常游两次泳。每个游泳运动员参加预赛,前12或16名将在决赛中比赛一次。为了让预赛更公平,预赛循环排名:

  最快的三名选手安排在最快的中心泳道,第二快的三名选手安排在前三组相邻的中心泳道,以此类推。

  如何构建一个对象来实现这种使用分配机制,并解释工厂模式?首先,设计一个耳光抽象类事件。

  1使用系统;

  2使用系统。收藏;

  3使用CsharpPats

  四

  5命名空间播种

  6 {

  7 ///摘要

  8 ///事件的摘要描述。

  9////摘要

  10公共抽象类事件{

  11个受保护的int numLanes

  12个受保护的数组列表游泳者;

  13

  14公共事件(字符串文件名,int lanes) {

  15 numLanes=车道;

  16游泳者=new ArrayList();

  17//从文件中读入游泳者

  18 csFile f=新的csFile(文件名);

  19 f . OpenForRead();

  20 string s=f . readline();

  21 while (s!=null) {

  22游泳者sw=新游泳者;

  23名游泳运动员。Add(软件);

  24s=f . readline();

  25 }

  26 f . close();

  27 }

  28公共抽象播种get Seeding();

  29公共抽象bool isPrelim();

  30公共抽象bool is final();

  31公共抽象bool isTimedFinal

  32 }

  33 }

  这些抽象方法表明具体的事件类应该实现什么。接下来,有两个从Event类派生的具体类,

  它们分别是PrelimEvent类和TimedFinalEvent类。这两个类的唯一区别是,一个类返回通道分配方法,另一个类返回另一个通道分配方法。我们还用以下方法定义了抽象类播种

  1使用系统;

  2使用系统。收藏;

  3命名空间播种

  4 {

  5 ///摘要

  6 ///种子设定的摘要描述。

  7////摘要

  8公共抽象类播种{

  9个受保护的int numLanes

  10个受保护的int[]通道;

  11公共抽象IEnumerator get hunters();

  12公共抽象int get count();

  13 public abstract int get heats();

  14受保护的抽象void seed();

  15 //-

  16受保护的void calcLaneOrder() {

  17 lanes=new int[numLanes];

  18 int mid=numLanes/2;

  19 if(奇数(numLanes))

  20 mid=mid 1;//从中间车道开始

  21 int incr=1;

  22 int ln=mid

  23//创建通道阵列

  24//中心到外部

  25 for(int I=0;我numLanesi ) {

  26车道[I]=ln;

  27 ln=中间增量;

  28 incr=-incr;

  29 if(增量0)

  30 incr=incr 1;

  31 }

  32 }

  33 //-

  34 private bool odd(int x) {

  35返回((x/2)*2)!=x);

  36 }

  37 }

  38 }

  接下来,创建播种的两个特定子类:直线播种类和环形播种类。PrelimEvent类将返回CircleSeeding的实例,而TimedFinalEvent类将返回StraightSeeding的实例。

  所以我们有两个架构:一个是关于事件的。

  一个好像是关于播种的。

  是的。

  在事件继承结构中(如下图)会看到两个事件的派生类,他们含有获取种子方法一个返回直播实例,另一个返回循环播种的实例。

  可以看出,它与我们前面的例子不同没有实际的工厂决策点。实例化哪一个事件类的决策就是决定实例化哪一个播种类

  的决策。

  在两个类继承体系结构中,尽管看起来是一对一的对应关系,但不是必须的。可以有许多这种事件类,而只有使用几种播种类。

  游泳者类

  除了说过的游泳者类含有名字、俱乐部、年龄、排位、时间以及选拔赛后的分组和泳道外,游泳运动员类我们并没有介绍太多事件。类从某个数据库

  读入游泳者数据,然后再某项赛事中调用获取种子方法时,将数据传给播种类。

  一使用系统;

  2使用CsharpPats

  3

  四命名空间播种

  5 {

  6 ///摘要

  7 ///游泳者的概要描述。

  8////摘要

  9公共级游泳运动员

  10 {

  11私有字符串名字,姓氏

  12个私人年龄;

  13私人弦乐社;

  14私人浮动时间;

  15

  私(同Internationalorganizations)国际组织热,巷16号;

  17 //-

  18公共游泳者(字符串数据线路){

  19 string tokenizer ST=new string tokenizer(dataline, );

  20字符串行号=ST . nexttoken();//忽略并放弃

  21 first name=ST . nexttoken();

  22姓氏=ST . nexttoken();

  23年龄=转换ToInt32 (st.nextToken().trim());

  24 club=st.nextToken().trim();

  25

  26字符串stime=st.nextToken().trim();

  27 int i=stime .(":")的索引;

  28 if (i 0) {

  29时间=时间。子串(0,I)时间。子串(一1);

  30 }

  31时间=转换100 .到单身(stime);

  32

  33 }

  34

  35 //-

  36 public void setLane(int ln) {

  37车道=ln

  38 }

  39 //-

  40 public int getLane() {

  41返回车道;

  42 }

  43 //-

  44 public void setHeat(int ht) {

  45热=ht

  46 }

  47 //-

  48 public int getHeat() {

  49回热;

  50 }

  51 //-

  52 public int getAge() {

  53回归年龄;

  54 }

  55 //-

  56 public float getTime() {

  57返回时间;

  58 }

  59 //-

  60公共字符串getName() {

  61返回名" "姓;

  62 }

  63 //-

  64公共字符串getClub() {

  65回归俱乐部;

  66 }

  67

  68 }

  69 }

  事件类

  我们在前面已经看到了抽象基类事件。在实际中,用它读入选手数据,并将其传给游泳者类的一个实例去进行分析。在抽象基类事件里,判断赛事是预赛、

  决赛还是计时决赛的方法都是空的、在派生类中会实现这些方法初步事件返回循环播种的一个实例

  一使用系统;

  2

  3命名空间播种

  4 {

  5 ///摘要

  6///PrelimEvent的摘要说明。

  7////摘要

  8公共类预事件:事件

  9 {

  10公共预活动(字符串文件名,整数车道):base(文件名,车道){

  11 }

  12//返回循环播种

  13公共覆盖播种getSeeding() {

  14回新圈赛(游泳、跳水);

  15 }

  16公共覆盖bool isPrelim() {

  17返回真实的

  18 }

  19公共覆盖bool isFinal() {

  20返回假;

  21 }

  22公共覆盖bool istimed final(){

  23返回假;

  24 }

  25 }

  26 }

  一使用系统;

  2

  3命名空间播种{

  4 ///摘要

  5///类描述将被游泳两次的事件

  6////摘要

  七公共类TimedFinalEvent:事件{

  8

  9 public timedfinalievent(string filename,int lanes):base(filename,lanes) {

  10 }

  11//返回直接播种类

  12公共覆盖播种getSeeding() {

  13名回归新直播员(游泳运动员、游泳运动员);

  14 }

  15公共覆盖bool isPrelim() {

  16返回假;

  17 }

  18公共覆盖bool isFinal() {

  19返回假;

  20 }

  21公共覆盖bool isTimedFinal

  22返回真实的

  23 }

  24 }

  25 }

  直接排位

  实际编写这个程序时,我们发现大多数工作都是在直接排位(直播)中完成的,为了循环排位(循环播放)而进行的改动相当少。

  实例化直播类,并拷如选手和泳道号。

  一个受保护的覆盖无效种子(){

  2//加载swmrs数组并对其排序

  3向上排序();

  四

  5 int lastHeat=count % numLanes

  6 if (lastHeat 3)

  7最后一次加热=3;//最后一次加热必须有3个或更多

  8 int最后泳道=计数-最后热度;

  9 numHeats=count/numLanes;

  10如果(最后车道0)

  11 numHeats

  12 int heats=numHeats

  13

  14//在每个游泳者的物品中放置热量和泳道

  15 int j=0;

  16 for(int I=0;我喜欢小巷;i ) {

  17游泳运动员SW=SW Mrs[I];

  西南18度。设置lanes(lanes[j]);

  19开关setHeat(加热);

  20 if (j=numLanes) {

  21次预赛-;

  22j=0;

  23 }

  24 }

  25//加入最后部分加热

  26 if (j numLanes)

  27预赛-;

  28j=0;

  29 for(int I=最后一条车道-1;我数;i ) {

  30游泳运动员SW=SW Mrs[I];

  西南31度。设置lanes(lanes[j]);

  32开关setHeat(加热);

  33 }

  34//从数组复制回数组列表

  35游泳者=new ArrayList();

  36 for(int I=0;我数;我)

  37名游泳运动员100 .添加(swmrs[I]);

  38 }

  循环排位

  循环播种

  类从直播类派生类中,因此一开始先调用父类的种子方法,然后重新安排赛事

  一个受保护的覆盖无效种子(){

  2 int圈;

  3

  4垒。seed();//默认使用直接种子

  5 if (numHeats=2 ) {

  6 if (numHeats=3)

  七圆=3;

  8其他

  9圆=2;

  10 int I=0;

  11 for(int j=0;j numLanesj ) {

  12 for(int k=0;k圈;k ) {

  13 swmrs[i].设置lanes(lanes[j]);

  14 swmrs[i ].setHeat(numHeats-k);

  15 }

  16 }

  17 }

  18 }

  其他工厂

  我们在前面略过了一个问题:读入运动员数据程序如何决定生成那一项赛事。再读入数据时,通过正确类型的事件来巧妙的实现这一点。

  一私有void init() {

  2//创建事件数组

  3 events=new ArrayList();

  四个事件1000个项目。添加( 500免费);

  5个事件1000个项目。添加( 100免费);

  6//并读入它们的数据

  七个事件添加(新的timedfinaleivent( 500免费。txt ,6));

  8个事件添加(新的PrelimEvent (100free.txt ,6));

  9 }

  很明显、这是一个需要事件工厂来决定生成哪一项赛事的例子,这里有涉及到前面的简单工厂了!

  什么场景下能使用工厂模式如一下情况

  1、一类无法预测他要创建的对象属于那一个类。

  2、一类用它的子类来指定所创建的对象。

  3、把要创建哪一类的信息局部化的时候。

简单工厂设计模式例子,工厂方法模式实例