大话设计模式
字体: 16 + -

第179章

大b:“游戏中会出现各种鸭子,一边游戏戏水,一边呱呱叫,我们设计了一个鸭子超类(duck),并让各种鸭子继承此类。”

java代码

publicabstractclassduck{

voidquack();//呱呱叫

voidswin();//游泳

abstractvoiddisplay();//鸭子外观不同,所以是抽象的

//other

}

publicclassmallardduckextendsduck{

publicvoiddisplay(){

//外观是绿头

}

}

publicclassredheadduckextendsduck{

publicvoiddisplay(){

//外观是红头

}

}

//otherextends

publicabstractclassduck{

voidquack();//呱呱叫

voidswin();//游泳

abstractvoiddisplay();//鸭子外观不同,所以是抽象的

//other

}

publicclassmallardduckextendsduck{

publicvoiddisplay(){

//外观是绿头

}

}

publicclassredheadduckextendsduck{

publicvoiddisplay(){

//外观是红头

}

}

//otherextends

大b:“现在多了个主意,要让鸭子能飞,那么你可能想到只要在duck类中加上fly()方法,然后让所有的鸭子都来继承这个方法。”

java代码

publicabstractclassduck{

voidquack();//呱呱叫

voidswin();//游泳

abstractvoiddisplay();//鸭子外观不同,所以是抽象的

fly();//刚加的会飞的方法,所有的子类都会继承

//other

}

publicabstractclassduck{

voidquack();//呱呱叫

voidswin();//游泳

abstractvoiddisplay();//鸭子外观不同,所以是抽象的

fly();//刚加的会飞的方法,所有的子类都会继承

//other

}

大b:“但是,可怕的问题就出来了:‘塑料橡皮鸭子’也会飞了,忽略了一件事,并非所有的鸭子都会飞。能想到继承,把橡皮鸭子类中的fly()方法覆盖掉,什么也不做。可是,如果以后要加入木头鸭子,不会飞也不会叫,你又想到了,把fly()从超类中取出来,做一个flyable()接口,同样的方式,设计一个会叫的接口quackable()。”

小a:“但是你没发现这么一来重复的代码会很多吗?”

大b:“现在我们知道使用继承并不能很好的解决问题,因为鸭子的行为在子类里不断的改变,让所有的子类都有这些行为是不恰当的。”

第一个设计原则:

找出应用中可能需要变化之处,把它独立出来,不要和那些不需要变化的代码混在一起。现在知道duck()类里的fly()和quack()会随着鸭子的不同而改变,我们把它从duck()类里取出来,写2个接口:

代码:

publicinterfaceflybehavior{

publicvoidfly();//飞行行为必须实现的接口

}

publicinterfacequackbehavior{

publicvoidquack();//叫行为必须实现的接口

}publicinterfaceflybehavior{publicvoidfly();//飞行行为必须实现的接口

}

publicinterfacequackbehavior{

publicvoidquack();//叫行为必须实现的接口

}

这样的设计可以让这2个动作行为与鸭子类无关,可以被其他的对象复用,也可以新增加一些行为。

第二个设计原则:

针对接口编程,而不是针对实现编程。

现在来整合下鸭子的行为:

代码:

1、duck()抽象类

publicabstractclassduck{

//为行为接口类型声明2个引用变量,所有的鸭子子类都继承它们

flybehaviorflybehavior;

quackbehaviorquackbehavior;

publicduck(){

}

//设定鸭子的行为,而不是在鸭子的构造器内实例化

publicvoidsetflybehavior(flybehaviorfb){

flybehavior=fb;

}

publicvoidsetquackbehavior(quackbehaviorqb){

quackbehavior=qb;

}

abstractvoiddisplay();//抽象外观方法

publicvoidperformfly(){

flybehavior.fly();//委托给会飞的行为类

}

publicvoidperformquack(){

quackbehavior.quack();//委托给会叫的行为类

}

publicvoidswim(){

system.out.println(“allducksfloat,evendecoys!”);

}

}

2、flybehavior()接口与2个行为实现类

publicinterfaceflybehavior{

publicvoidfly();

}

publicclassflynowayimplementsflybehavior{

publicvoidfly(){

system.out.println(“icantfly”);

}

}

publicclassflywithwingsimplementsflybehavior{

publicvoidfly(){

system.out.println(“imflying!”);

}

}

3、quackbehavior()接口与2个行为实现类

publicinterfacequackbehavior{

publicvoidquack();

}

publicclassquackimplementsquackbehavior{

publicvoidquack(){

system.out.println(“quack”);

}

}

publicclassmutequackimplementsquackbehavior{

publicvoidquack(){

system.out.println(“《silence》”);

}

}

4、来看看如何设定flybehavior和quackbehavior的实例变量(继承)

publicclassmallardduckextendsduck{

publicmallardduck(){

//绿头鸭子使用quack类处理呱呱叫,所以当performquack被调用时,叫的责任被委托给quack对象,

//而我们得到了真正的呱呱叫

quackbehavior=newquack();

//使用flywithwings作为其flybehavior类型

flybehavior=newflywithwings();

}

publicvoiddisplay(){

system.out.println(“imarealmallardduck”);

}

}

5、制造一个新的鸭子类型

publicclassmodelduckextendsduck{

publicmodelduck(){

flybehavior=newflynoway();//一开始我们的鸭子是不会飞的

quackbehavior=newquack();

}

publicvoiddisplay(){

system.out.println(“imamodelduck”);

}

}

6、建立一个新的flybehavior类型,火箭动力的飞行行为

publicclassflyrocketpoweredimplementsflybehavior{

publicvoidfly(){

system.out.println(“imflyingwitharocket”);

}

}

7、测试类

publicclassminiducksimulator{

publicstaticvoidmain(string[]args){

duckmallard=newmallardduck();

//这会调用mallardduck继承来的performquack方法,进而委托给该对象的quackbehavion对象处理

//也就是说调用继承来的quackbehavion引用对象的quack()方法

mallard.performquack();

mallard.performfly();

duckmodel=newmodelduck();

//第一次调用performfly会被委托给flybahavion对象,

//也就是flynoway实例,该对象是在模型鸭子构造器中设置的

model.performfly();

//这会调用继承来的setter方法,把flyrocketpowered火箭动力飞行行为设定到模型鸭子中,牛吧……

model.setflybehavior(newflyrocketpowered());

//如果成功了,就意味着模型鸭子可以动态的改变它的飞行行为

model.performfly();

}

}