Factory Method工厂方法(创建型模式)
2007-03-21 10:02
435 查看
从耦合关系谈起
耦合关系直接决定着软件面对变化时的行为
l 模块与模块之间的紧耦合使得软件面对变化时,相关的模块都要随之更改。
l 模块与模块之间的松耦合使得软件面对变化时,一些模块更容易被替换或者更改,但其他模块保持不变。
动机:
在软件系统中,经常面临着“某个对象”的创建工作;由于需求的变化,这个对象经常面临着剧烈的变化,但是它却拥有比较稳定的接口。
如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖该对象的对象”不随着需求改变而改变?
意图:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。
Factory Method模式的几个要点:
l Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。
l Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
l Factory Method模式解决“单个对象”的需求变化,Abstract Factory模式解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化。
设计一个抽象类Event
Event.cs代码示例:
using System;
using System.Collections;
using CsharpPats;
namespace Seeding
...{
/**//// <summary>
/// Summary description for Event.
/// </summary>
public abstract class Event ...{
protected int numLanes;
protected ArrayList swimmers;
public Event(string filename, int lanes) ...{
numLanes = lanes;
swimmers = new ArrayList();
//read in swimmers from file
csFile f = new csFile(filename);
f.OpenForRead ();
string s = f.readLine();
while (s != null) ...{
Swimmer sw = new Swimmer(s);
swimmers.Add (sw);
s = f.readLine();
}
f.close();
}
public abstract Seeding getSeeding();
public abstract bool isPrelim();
public abstract bool isFinal();
public abstract bool isTimedFinal();
}
}
由Event类派生两个具体的类,分别为PrelimEvent类(返回一种泳道分配方式)和TimedFinalEvent类(返回另一种泳道分配方式)
PrelimEvent.cs代码示例:
using System;
namespace Seeding
...{
/**//// <summary>
/// Summary description for PrelimEvent.
/// </summary>
public class PrelimEvent:Event
...{
public PrelimEvent(string filename, int lanes):base(filename,lanes) ...{
}
//return circle seeding
public override Seeding getSeeding() ...{
return new CircleSeeding(swimmers, numLanes);
}
public override bool isPrelim() ...{
return true;
}
public override bool isFinal() ...{
return false;
}
public override bool isTimedFinal() ...{
return false;
}
}
}
TimedFinalEvent.cs代码示例:
using System;
namespace Seeding ...{
/**//// <summary>
///class describes an event that will be swum twice
/// </summary>
public class TimedFinalEvent:Event ...{
public TimedFinalEvent(string filename, int lanes):base(filename, lanes) ...{
}
//return StraightSeeding class
public override Seeding getSeeding() ...{
return new StraightSeeding(swimmers, numLanes);
}
public override bool isPrelim() ...{
return false;
}
public override bool isFinal() ...{
return false;
}
public override bool isTimedFinal() ...{
return true;
}
}
}
再定义一个抽象类Seeding
Seeding.cs代码示例:
using System;
using System.Collections ;
namespace Seeding
...{
/**//// <summary>
/// Summary description for Seeding.
/// </summary>
public abstract class Seeding ...{
protected int numLanes;
protected int[] lanes;
public abstract IEnumerator getSwimmers();
public abstract int getCount();
public abstract int getHeats();
protected abstract void seed();
//--------------------------------
protected void calcLaneOrder() ...{
lanes = new int[numLanes];
int mid = numLanes / 2;
if (odd(numLanes))
mid = mid + 1; //start in middle lane
int incr = 1;
int ln = mid;
//create array of lanes from
//center to outside
for (int i=0; i< numLanes; i++) ...{
lanes[i] = ln;
ln = mid + incr;
incr = - incr;
if (incr > 0)
incr=incr+1;
}
}
//--------------------------------
private bool odd(int x) ...{
return(((x / 2)*2) != x);
}
}
}
接下来创建两个具体的Seeding子类:StraightSeeding类和CircleSeeding类。PrelimEvent类会返回一个CircleSeeding的实例,而TImedFinalEvent类会返回一个StraightSeeding的实例。这样,我们有两个继承体系结构:一个是关于Event的,一个是关于Seeding的。
Swimmer.cs代码示例:
using System;
using CsharpPats;
namespace Seeding
...{
/**//// <summary>
/// Summary description for Swimmer.
/// </summary>
public class Swimmer
...{
private string firstName, lastName;
private int age;
private string club;
private float time;
private int heat, lane;
//--------------------------------------
public Swimmer(String dataline) ...{
StringTokenizer st = new StringTokenizer(dataline, " ");
string lineNumber = st.nextToken(); //ignore and discard
firstName = st.nextToken();
lastName = st.nextToken();
age = Convert.ToInt32 (st.nextToken().Trim());
club = st.nextToken().Trim();
string stime = st.nextToken().Trim();
int i = stime.IndexOf(":");
if (i > 0) ...{
stime = stime.Substring(0, i) + stime.Substring (i+1);
}
time = Convert.ToSingle ( stime);
}
//-------------------------------
public void setLane(int ln) ...{
lane = ln;
}
//-------------------------------
public int getLane() ...{
return lane;
}
//-------------------------------
public void setHeat(int ht) ...{
heat = ht;
}
//-------------------------------
public int getHeat() ...{
return heat;
}
//-------------------------------
public int getAge() ...{
return age;
}
//-------------------------------
public float getTime() ...{
return time;
}
//-------------------------------
public string getName() ...{
return firstName+" "+lastName;
}
//-------------------------------
public string getClub() ...{
return club;
}
}
}
CsFile.cs代码示例:
using System;
using System.IO ;
namespace CsharpPats
...{
/**//// <summary>
/// A simple file handlng class
/// </summary>
public class csFile
...{
private string fileName;
StreamReader ts;
StreamWriter ws;
private bool opened, writeOpened;
//-----------
public csFile() ...{
init();
}
//-----------
private void init() ...{
opened = false;
writeOpened = false;
}
//-----------
public csFile(string file_name) ...{
fileName = file_name;
init();
}
//-----------
public bool OpenForRead(string file_name)...{
fileName = file_name;
try ...{
ts = new StreamReader (fileName);
opened=true;
}
catch(FileNotFoundException e) ...{
return false;
}
return true;
}
//-----------
public bool OpenForRead() ...{
return OpenForRead(fileName);
}
//-----------
public string readLine() ...{
return ts.ReadLine ();
}
//-----------
public void writeLine(string s) ...{
ws.WriteLine (s);
}
//-----------
public void close() ...{
if (opened)
ts.Close ();
if(writeOpened)
ws.Close();
}
//-----------
public bool OpenForWrite() ...{
return OpenForWrite(fileName);
}
//-----------
public bool OpenForWrite(string file_name) ...{
try...{
ws = new StreamWriter (file_name);
fileName = file_name;
writeOpened = true;
return true;
}
catch(FileNotFoundException e) ...{
return false;
}
}
}
}
StringTokenizer.cs代码示例:
using System;
namespace CsharpPats
...{
//String Tokenizer class
public class StringTokenizer ...{
private string data, delimiter;
private string[] tokens;
private int index;
public StringTokenizer(string dataLine) ...{
init(dataLine, " ");
}
private void init(String dataLine, string delim) ...{
delimiter = delim;
data = dataLine;
tokens = data.Split (delimiter.ToCharArray() );
index = 0;
}
public StringTokenizer(string dataLine, string delim) ...{
init(dataLine, delim);
}
public bool hasMoreElements() ...{
return (index < (tokens.Length));
}
public string nextToken() ...{
return nextElement();
}
public string nextElement() ...{
string s = tokens[index++];
while((s.Length <=0) && (index<tokens.Length ))
s = tokens[index++];
return s;
}
}
}
事件代码:
private void init() ...{
//create array of events
events = new ArrayList ();
lsEvents.Items.Add ("500 Free");
lsEvents.Items.Add ("100 Free");
//and read in their data
events.Add (new TimedFinalEvent ("500free.txt", 6));
events.Add (new PrelimEvent ("100free.txt", 6));
}
private void lsEvents_SelectedIndexChanged(object sender, System.EventArgs e) ...{
int index = lsEvents.SelectedIndex ;
Event ev = (Event)events[index];
Seeding sd = ev.getSeeding();
IEnumerator en = sd.getSwimmers();
lsSwimmers.Items.Clear() ;
while(en.MoveNext ()) ...{
Swimmer sw = (Swimmer)en.Current ;
lsSwimmers.Items.Add(sw.getHeat()+" "+sw.getLane()+" "+sw.getName()+" "+sw.getTime());
}
}
下列情况下,应该考虑使用工厂方法:
l 一个类无法预测它要创建的对象属于哪一个类。
l 一个类用它的子类来指定所创建的对象。
l 把要创建哪一个类的信息局部化的时候。
对于实现工厂模式,还需要考虑几个问题:
l 基类是一个抽象类,模式必须返回一个完整的可工作的类。
l 基类包含默认方法,除非默认方法不能胜任,才会调用这些方法。
l 可以将参数传递给工厂,告诉工厂返回哪一个类型的类。这种情况下,类可以共享相同的方法名,但完成的工作可以不同。
耦合关系直接决定着软件面对变化时的行为
l 模块与模块之间的紧耦合使得软件面对变化时,相关的模块都要随之更改。
l 模块与模块之间的松耦合使得软件面对变化时,一些模块更容易被替换或者更改,但其他模块保持不变。
动机:
在软件系统中,经常面临着“某个对象”的创建工作;由于需求的变化,这个对象经常面临着剧烈的变化,但是它却拥有比较稳定的接口。
如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖该对象的对象”不随着需求改变而改变?
意图:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。
Factory Method模式的几个要点:
l Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。
l Factory Method模式通过面向对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
l Factory Method模式解决“单个对象”的需求变化,Abstract Factory模式解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化。
设计一个抽象类Event
Event.cs代码示例:
using System;
using System.Collections;
using CsharpPats;
namespace Seeding
...{
/**//// <summary>
/// Summary description for Event.
/// </summary>
public abstract class Event ...{
protected int numLanes;
protected ArrayList swimmers;
public Event(string filename, int lanes) ...{
numLanes = lanes;
swimmers = new ArrayList();
//read in swimmers from file
csFile f = new csFile(filename);
f.OpenForRead ();
string s = f.readLine();
while (s != null) ...{
Swimmer sw = new Swimmer(s);
swimmers.Add (sw);
s = f.readLine();
}
f.close();
}
public abstract Seeding getSeeding();
public abstract bool isPrelim();
public abstract bool isFinal();
public abstract bool isTimedFinal();
}
}
由Event类派生两个具体的类,分别为PrelimEvent类(返回一种泳道分配方式)和TimedFinalEvent类(返回另一种泳道分配方式)
PrelimEvent.cs代码示例:
using System;
namespace Seeding
...{
/**//// <summary>
/// Summary description for PrelimEvent.
/// </summary>
public class PrelimEvent:Event
...{
public PrelimEvent(string filename, int lanes):base(filename,lanes) ...{
}
//return circle seeding
public override Seeding getSeeding() ...{
return new CircleSeeding(swimmers, numLanes);
}
public override bool isPrelim() ...{
return true;
}
public override bool isFinal() ...{
return false;
}
public override bool isTimedFinal() ...{
return false;
}
}
}
TimedFinalEvent.cs代码示例:
using System;
namespace Seeding ...{
/**//// <summary>
///class describes an event that will be swum twice
/// </summary>
public class TimedFinalEvent:Event ...{
public TimedFinalEvent(string filename, int lanes):base(filename, lanes) ...{
}
//return StraightSeeding class
public override Seeding getSeeding() ...{
return new StraightSeeding(swimmers, numLanes);
}
public override bool isPrelim() ...{
return false;
}
public override bool isFinal() ...{
return false;
}
public override bool isTimedFinal() ...{
return true;
}
}
}
再定义一个抽象类Seeding
Seeding.cs代码示例:
using System;
using System.Collections ;
namespace Seeding
...{
/**//// <summary>
/// Summary description for Seeding.
/// </summary>
public abstract class Seeding ...{
protected int numLanes;
protected int[] lanes;
public abstract IEnumerator getSwimmers();
public abstract int getCount();
public abstract int getHeats();
protected abstract void seed();
//--------------------------------
protected void calcLaneOrder() ...{
lanes = new int[numLanes];
int mid = numLanes / 2;
if (odd(numLanes))
mid = mid + 1; //start in middle lane
int incr = 1;
int ln = mid;
//create array of lanes from
//center to outside
for (int i=0; i< numLanes; i++) ...{
lanes[i] = ln;
ln = mid + incr;
incr = - incr;
if (incr > 0)
incr=incr+1;
}
}
//--------------------------------
private bool odd(int x) ...{
return(((x / 2)*2) != x);
}
}
}
接下来创建两个具体的Seeding子类:StraightSeeding类和CircleSeeding类。PrelimEvent类会返回一个CircleSeeding的实例,而TImedFinalEvent类会返回一个StraightSeeding的实例。这样,我们有两个继承体系结构:一个是关于Event的,一个是关于Seeding的。
Swimmer.cs代码示例:
using System;
using CsharpPats;
namespace Seeding
...{
/**//// <summary>
/// Summary description for Swimmer.
/// </summary>
public class Swimmer
...{
private string firstName, lastName;
private int age;
private string club;
private float time;
private int heat, lane;
//--------------------------------------
public Swimmer(String dataline) ...{
StringTokenizer st = new StringTokenizer(dataline, " ");
string lineNumber = st.nextToken(); //ignore and discard
firstName = st.nextToken();
lastName = st.nextToken();
age = Convert.ToInt32 (st.nextToken().Trim());
club = st.nextToken().Trim();
string stime = st.nextToken().Trim();
int i = stime.IndexOf(":");
if (i > 0) ...{
stime = stime.Substring(0, i) + stime.Substring (i+1);
}
time = Convert.ToSingle ( stime);
}
//-------------------------------
public void setLane(int ln) ...{
lane = ln;
}
//-------------------------------
public int getLane() ...{
return lane;
}
//-------------------------------
public void setHeat(int ht) ...{
heat = ht;
}
//-------------------------------
public int getHeat() ...{
return heat;
}
//-------------------------------
public int getAge() ...{
return age;
}
//-------------------------------
public float getTime() ...{
return time;
}
//-------------------------------
public string getName() ...{
return firstName+" "+lastName;
}
//-------------------------------
public string getClub() ...{
return club;
}
}
}
CsFile.cs代码示例:
using System;
using System.IO ;
namespace CsharpPats
...{
/**//// <summary>
/// A simple file handlng class
/// </summary>
public class csFile
...{
private string fileName;
StreamReader ts;
StreamWriter ws;
private bool opened, writeOpened;
//-----------
public csFile() ...{
init();
}
//-----------
private void init() ...{
opened = false;
writeOpened = false;
}
//-----------
public csFile(string file_name) ...{
fileName = file_name;
init();
}
//-----------
public bool OpenForRead(string file_name)...{
fileName = file_name;
try ...{
ts = new StreamReader (fileName);
opened=true;
}
catch(FileNotFoundException e) ...{
return false;
}
return true;
}
//-----------
public bool OpenForRead() ...{
return OpenForRead(fileName);
}
//-----------
public string readLine() ...{
return ts.ReadLine ();
}
//-----------
public void writeLine(string s) ...{
ws.WriteLine (s);
}
//-----------
public void close() ...{
if (opened)
ts.Close ();
if(writeOpened)
ws.Close();
}
//-----------
public bool OpenForWrite() ...{
return OpenForWrite(fileName);
}
//-----------
public bool OpenForWrite(string file_name) ...{
try...{
ws = new StreamWriter (file_name);
fileName = file_name;
writeOpened = true;
return true;
}
catch(FileNotFoundException e) ...{
return false;
}
}
}
}
StringTokenizer.cs代码示例:
using System;
namespace CsharpPats
...{
//String Tokenizer class
public class StringTokenizer ...{
private string data, delimiter;
private string[] tokens;
private int index;
public StringTokenizer(string dataLine) ...{
init(dataLine, " ");
}
private void init(String dataLine, string delim) ...{
delimiter = delim;
data = dataLine;
tokens = data.Split (delimiter.ToCharArray() );
index = 0;
}
public StringTokenizer(string dataLine, string delim) ...{
init(dataLine, delim);
}
public bool hasMoreElements() ...{
return (index < (tokens.Length));
}
public string nextToken() ...{
return nextElement();
}
public string nextElement() ...{
string s = tokens[index++];
while((s.Length <=0) && (index<tokens.Length ))
s = tokens[index++];
return s;
}
}
}
事件代码:
private void init() ...{
//create array of events
events = new ArrayList ();
lsEvents.Items.Add ("500 Free");
lsEvents.Items.Add ("100 Free");
//and read in their data
events.Add (new TimedFinalEvent ("500free.txt", 6));
events.Add (new PrelimEvent ("100free.txt", 6));
}
private void lsEvents_SelectedIndexChanged(object sender, System.EventArgs e) ...{
int index = lsEvents.SelectedIndex ;
Event ev = (Event)events[index];
Seeding sd = ev.getSeeding();
IEnumerator en = sd.getSwimmers();
lsSwimmers.Items.Clear() ;
while(en.MoveNext ()) ...{
Swimmer sw = (Swimmer)en.Current ;
lsSwimmers.Items.Add(sw.getHeat()+" "+sw.getLane()+" "+sw.getName()+" "+sw.getTime());
}
}
下列情况下,应该考虑使用工厂方法:
l 一个类无法预测它要创建的对象属于哪一个类。
l 一个类用它的子类来指定所创建的对象。
l 把要创建哪一个类的信息局部化的时候。
对于实现工厂模式,还需要考虑几个问题:
l 基类是一个抽象类,模式必须返回一个完整的可工作的类。
l 基类包含默认方法,除非默认方法不能胜任,才会调用这些方法。
l 可以将参数传递给工厂,告诉工厂返回哪一个类型的类。这种情况下,类可以共享相同的方法名,但完成的工作可以不同。
相关文章推荐
- 创建型模式-工厂方法 Creational Patterns-Factory Method
- 五、Factory Method 工厂方法(创建型模式)
- 设计模式(2)-创建型-工厂方法(Factory method)(个人笔记)
- 设计模式(三):创建型模式—Factory Method(工厂方法)
- 设计模式(三)、FACTORY METHOD(工厂方法)---对象创建型模式
- Factory Method(工厂方法)-对象创建型模式
- 创建型模式-工厂方法
- 【设计模式】创建型模式之工厂方法Factory Method
- 创建型模式(一):FactoryMethod ( 工厂方法 )
- 工厂方法 (Factory Method) 创建型模式
- (第Ⅱ部分 创建型模式篇) 第4章 工厂方法(Factory Method)
- 创建型设计模式之手工打造、简单工厂、工厂方法和抽象工厂(新)
- 跟着实例学习设计模式(3)-工厂方法(创建型)
- 【创建型设计模式】-简单工厂方法设计模式
- [设计模式-创建型]工厂方法(Factory Method)
- java设计模式(创建型)之工厂方法模式
- 简单工厂,Factory Method(工厂方法)和Abstract Factory(抽象工厂)模式
- 工厂方法模式GoF23种设计模式之创建型模式之工厂方法模式
- 1.3 Factory Method(工厂方法) -- 对象创建型模式
- 创建型模式-简单工厂方法(simple_factory)