Factory Method工厂方法(创建型模式)

从耦合关系谈起

耦合关系直接决定着软件面对变化时的行为

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         可以将参数传递给工厂,告诉工厂返回哪一个类型的类。这种情况下,类可以共享相同的方法名,但完成的工作可以不同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值