从耦合关系谈起
耦合关系直接决定着软件面对变化时的行为
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;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
namespace
Seeding
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//// <summary>
/// Summary description for Event.
/// </summary>
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public abstract class Event ...{
protected int numLanes;
protected ArrayList swimmers;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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();
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
namespace
Seeding
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//// <summary>
/// Summary description for PrelimEvent.
/// </summary>
public class PrelimEvent:Event
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public PrelimEvent(string filename, int lanes):base(filename,lanes) ...{
}
//return circle seeding
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public override Seeding getSeeding() ...{
return new CircleSeeding(swimmers, numLanes);
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public override bool isPrelim() ...{
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public override bool isFinal() ...{
return false;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public override bool isTimedFinal() ...{
return false;
}
}
}
TimedFinalEvent.cs
代码示例:
using
System;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
namespace
Seeding
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//// <summary>
///class describes an event that will be swum twice
/// </summary>
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public class TimedFinalEvent:Event ...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public TimedFinalEvent(string filename, int lanes):base(filename, lanes) ...{
}
//return StraightSeeding class
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public override Seeding getSeeding() ...{
return new StraightSeeding(swimmers, numLanes);
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public override bool isPrelim() ...{
return false;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public override bool isFinal() ...{
return false;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public override bool isTimedFinal() ...{
return true;
}
}
}
再定义一个抽象类Seeding
Seeding.cs代码示例:
using
System;
using
System.Collections ;
namespace
Seeding
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//// <summary>
/// Summary description for Seeding.
/// </summary>
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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();
//--------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
for (int i=0; i< numLanes; i++) ...{
lanes[i] = ln;
ln = mid + incr;
incr = - incr;
if (incr > 0)
incr=incr+1;
}
}
//--------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
namespace
Seeding
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//// <summary>
/// Summary description for Swimmer.
/// </summary>
public class Swimmer
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
private string firstName, lastName;
private int age;
private string club;
private float time;
private int heat, lane;
//--------------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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(":");
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
if (i > 0) ...{
stime = stime.Substring(0, i) + stime.Substring (i+1);
}
time = Convert.ToSingle ( stime);
}
//-------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void setLane(int ln) ...{
lane = ln;
}
//-------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public int getLane() ...{
return lane;
}
//-------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void setHeat(int ht) ...{
heat = ht;
}
//-------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public int getHeat() ...{
return heat;
}
//-------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public int getAge() ...{
return age;
}
//-------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public float getTime() ...{
return time;
}
//-------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public string getName() ...{
return firstName+" "+lastName;
}
//-------------------------------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public string getClub() ...{
return club;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
}
}
CsFile.cs代码示例:
using
System;
using
System.IO ;
namespace
CsharpPats
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//// <summary>
/// A simple file handlng class
/// </summary>
public class csFile
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
private string fileName;
StreamReader ts;
StreamWriter ws;
private bool opened, writeOpened;
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public csFile() ...{
init();
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
private void init() ...{
opened = false;
writeOpened = false;
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public csFile(string file_name) ...{
fileName = file_name;
init();
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public bool OpenForRead(string file_name)...{
fileName = file_name;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
try ...{
ts = new StreamReader (fileName);
opened=true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
catch(FileNotFoundException e) ...{
return false;
}
return true;
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public bool OpenForRead() ...{
return OpenForRead(fileName);
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public string readLine() ...{
return ts.ReadLine ();
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void writeLine(string s) ...{
ws.WriteLine (s);
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void close() ...{
if (opened)
ts.Close ();
if(writeOpened)
ws.Close();
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public bool OpenForWrite() ...{
return OpenForWrite(fileName);
}
//-----------
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public bool OpenForWrite(string file_name) ...{
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
try...{
ws = new StreamWriter (file_name);
fileName = file_name;
writeOpened = true;
return true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
catch(FileNotFoundException e) ...{
return false;
}
}
}
}
StringTokenizer.cs代码示例:
using
System;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
namespace
CsharpPats
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
//String Tokenizer class
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public class StringTokenizer ...{
private string data, delimiter;
private string[] tokens;
private int index;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public StringTokenizer(string dataLine) ...{
init(dataLine, " ");
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
private void init(String dataLine, string delim) ...{
delimiter = delim;
data = dataLine;
tokens = data.Split (delimiter.ToCharArray() );
index = 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public StringTokenizer(string dataLine, string delim) ...{
init(dataLine, delim);
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public bool hasMoreElements() ...{
return (index < (tokens.Length));
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public string nextToken() ...{
return nextElement();
}
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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() ;
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
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
可以将参数传递给工厂,告诉工厂返回哪一个类型的类。这种情况下,类可以共享相同的方法名,但完成的工作可以不同。