最近学习《大话设计模式》,在学习的过程中又加深了对OO的理解,诸如abstract和virtual的区别之类的问题有了清晰的认识。今天通过装饰模式,重温OO的继承,巩固子类于父类的构造函数调用,子类调用父类方法等问题。
先看一段代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Person { public Person() { Console.WriteLine("Person“); } } class Man : Person { public Man() { Console.WriteLine("Man"); }
}
|
然后我们在主函数中实例化子类Man
结果会怎样?学习过OO的新手都知道结果是

在实例化Man的时候却优先带出了父类Person,这是因为Man作为子类,将继承父类Person的方法(当然,是共有的,即public,若是爸爸的存折,小孩子当然不能拿过来玩),也就是子类实例化时,把父类能够继承的方法、属性”拷贝“到自身为己用。这是一个倒推的过程,从金字塔的底端一直找到最高端,然后从上到下”展现“出来。
简单的例子便于了解,而复杂一点的就不太容易看明白了,下面请看:
装饰模式,动态的给一个对象添加一些额外的职责,就增加功能来说,设计模式生成子类更为灵活。
源代码引用自《大话设计模式》
Person类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Person { string name; public Person() { } public Person(string name) { this.name = name; } public virtual void show() { Console.WriteLine("装扮的{0}",name); } }
|
Finery类:(继承Person)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Finery : Person { protected Person component; public Finery() { } public void Decorator(Person component) { this.component = component; } public override void show() { if (component != null) { component.show(); } }
|
杂类: (继承Finery)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class LeatherShoes : Finery { public override void show() { Console.WriteLine("LeatherShoes"); base.show(); } } class BigTrouser : Finery { public override void show() { Console.WriteLine("Big Trouser"); base.show(); } } class Tshirt : Finery { public override void show() { Console.WriteLine("T-shirt"); base.show(); } }
|
先分析一下,LeatherShoes,BigTrouser和Tshirt均继承自Finery,也就是说对这三个类实例化时,先调用的是Finery的构造函数。Finery中的Decorator方法由于是public,则同样被“拷贝”到各子类中为它们所用。而Finery又继承自Person类,当Finery构造函数调用时,又优先调用了Person的构造函数,并“拷贝”了Person的方法。
最后的结果应该是:
实例化LeatherShoes,BigTrouser和Tshirt任一个时
Person的构造函数被调用(是无参数的)
Person的show方法作为虚方法被拷贝至Finery
Finery的构造函数被调用
Finery重写了虚方法show
子类LeatherShoes,BigTrouser和Tshirt 的构造函数被调用
子类LeatherShoes,BigTrouser和Tshirt重写了虚方法show
即是一个倒推,顺寻展示的过程
在子类LeatherShoes,BigTrouser和Tshirt中的show方法中我们可以看到
1 2
| Console.WriteLine("***"); base.show();
|
这样的语句有何作用?
同实例化一样,也是倒推的过程,只不过这次针对的不是构造函数,而是show这个方法了。
具体完整的看一遍:
1 2 3 4 5 6 7 8 9 10 11
| Person my = new Person("Sonic"); Console.WriteLine("Decorator one:"); LeatherShoes qx = new LeatherShoes(); BigTrouser kk = new BigTrouser(); Tshirt dtx = new Tshirt(); qx.Decorator(my); kk.Decorator(qx); dtx.Decorator(kk); dtx.show();
|
Person的实例化传递了参数“Sonic”,这时调用的是Person的带参数构造函数
1 2 3 4 5 6 7
| public Person(string name) { this.name = name; } LeatherShoes qx = new LeatherShoes(); BigTrouser kk = new BigTrouser(); Tshirt dtx = new Tshirt();
|
三个子类的实例化,其倒推和展示过程已经讲过
这是LeatherShoes的对象 qx 继承了父类Finery的方法Decorator,参数是Person的对象my。
来看一下Finery的Decorator是做什么的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| protected Person component; public void Decorator(Person component) { this.component = component; } public override void show() { if (component != null) { component.show(); } }
|
首先定义一个Person对象component,这时 component 应为null,若此时我们没有传进来
qx.Decorator(my),而直接调用Finery的show,那么
component.show()是不执行的,也就是Person中的show不执行。现在我们将my传进来,component = my,将Person的两个对象建立起联系,此时让
Finery执行show,那么component的show 即 my的show,也就是名字为“Sonic”的Person将show出来。(有点绕)
当然,我们这里没有让它执行show,只是通过Decorator把参数传了进去。因为现在进行的是装饰的过程,没有装饰完是不需要展示出来的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| kk.Decorator(qx); dtx.Decorator(kk); dtx.show(); base.show()
|