您的位置:首页 > 其它

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         可以将参数传递给工厂,告诉工厂返回哪一个类型的类。这种情况下,类可以共享相同的方法名,但完成的工作可以不同。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息