編程中經常遇到很多條件,以及條件套條件的情況,以至於一個方法會寫得非常地長。有多種方法可以規避這個問題。比如反射,策略模式,表驅動等等。先拋開這些方法不講,從根本需求來探索這個過程。
一個switch結構可能是這樣:
swicth(case)
case 1:
//do1
break;
case 2:
//do2
break;
.....
這裡注釋的do部分代碼可能會是很多很多行,以及嵌套switch,if結構。
進一步,這個模型演化成
swicth(case)
case 1:
do1();
break;
case 2:
do2();
break;
.....
do1(){}
do2(){}
也就是將裡面的代碼模組化。這個方法有效減小了一個方法的代碼長度。實際上這就是一個映射關係的調用。建立映射關係,用Hash結構和delegate就可以避免使用switch了。
delegate void funtionptr();
Dictionary<int, funtionptr> dict = new Dictionary<int, funtionptr>();
dict.Add(1,do1);
dict.Add(2,do2);
int parm = 0;
if(dict.ContainKey(parm)){
dict[parm].Invoke();
}
do1(){}
do2(){}
這個方法實際上就是表驅動,因為C#中一般不用指標,因此用delegate代替了指標的作用。而java中既沒有指標也沒有delegate怎麼辦呢?那就用介面類比指標。
(這裡就用C#的文法了,不使用JAVA了)
interface FactionFace{
void do();
}
class FactionFaceImpl1 : FactionFace{
public void do(){}
}
class FactionFaceImpl2 : FactionFace{
public void do(){}
}
Dictionary<int, FactionFace> dict = new Dictionary<int, FactionFace>();
dict.Add(1,new FactionFaceImpl1());
dict.Add(2,new FactionFaceImpl2());
int parm = 0;
if(dict.ContainKey(parm)){
dict[parm].do();
}
可以看出,實際上,上面的代碼就是策略模式的簡單實現了。(OH~~原理策略模式這麼就來的~~)
可以看出,這裡實際上是依靠一個字典來維護條件和調用的關係的。那如果沒有這個字典來維護怎麼辦呢?代碼再次演化:
interface FactionFace{
void do();
}
class FactionFaceImpl1 : FactionFace{
public void do(){}
}
class FactionFaceImpl2 : FactionFace{
public void do(){}
}
string parm = "FactionFaceImpl2";
FactionFace ff = Type.GetType(parm) as FactionFace;
ff.do();
OH~~這就是簡單的反射了。再複雜一些就可以搞成原廠模式,外掛程式模式了。
可以看出,用字典來維護映射關係就可以避免使用反射。(這個是不是一般規律,貧道沒本事證明,起碼這裡是適應的。)
再來看try...catch...
delegate void forException(Exception ex);
public void forAException(Exception ex) {Console.WriteLine("AException");}
public void forAAException(Exception ex) {Console.WriteLine("AAException");}
public void forBException(Exception ex) {Console.WriteLine("BException");}
public void test() {
Dictionary<int, forException> dict = new Dictionary<int, forException>();
dict.Add(0, forAException);
dict.Add(1, forAException);
dict.Add(11, forAAException);
dict.Add(2, forBException);
try {
throw new AAException();
} catch (Exception ex)
{
if (ex is OException) {
OException eex = ex as OException;
if (dict.ContainsKey(eex.Index)) {
dict[eex.Index].Invoke(ex);
}
}
}
}
public class OException : Exception {public virtual int Index { get { return 0; } }}
public class AException : OException {public override int Index {get {return 1;}}}
public class AAException : AException {public override int Index {get {return 11;}}}
public class BException : OException {public override int Index {get {return 2;}}
這裡為啥要有個Index屬性呢?其實就是建立個對應的關係,而不是靠名字去維護。去掉這個屬性,直接使用ex.GeType()然後擷取名字類名也一樣可以建立對應關係。