初读《Head First》,自己的小记录。因为最近开始用c#,所以代码也用c#表示吧。(我知道写的很烂,但是我强迫自己要稍微写一下。。所以我才能真的认真看,并稍微有点思考的样子
首先是一个有关鸭子的系统。
Duck是鸭子的抽象类,MallardDuck,RedheadDuck是两种鸭子的具体类。他们都会quack和swim。
public abstract class Duck{
public abstract void display ();
public void quack(){
Debug.Log ("quack");
}
public void swim(){
Debug.Log ("swim");
}
}
public class MallardDuck : Duck{
public override void display(){
Debug.Log("MallardDuck display");
}
}
public class RedheadDuck : Duck{
public override void display(){
Debug.Log("RedheadDuck display");
}
}
添加完橡皮鸭后,需要同display一样重载quack(因为叫声不一样
似乎这样就可以暂时解决了。
但是当我们想给鸭子添加fly行为时,又要对橡皮鸭的fly特殊处理(因为他没法飞
于是发现了, 鸭子的行为经常产生变化,且容易引起代码的修改。
所以,我们希望将变化的部分单独拆开来,这样需要改变时,我们可以很轻易的修改或者扩充。这样不用管稳定的部分,减少我们的工作量。
将fly和quack行为单独封装出来。
每个具体鸭子都拥有 fly和quack行为接口,并且具体鸭子类可以在运行时指定具体行为。
同时我们为Duck添加 setBehavior的功能,以便更灵活的动态改变行为。
public abstract class Duck{
public QuackBehavior quackBehavior;
public FlyBehavior flyBehavior;
public void performQuack(){
quackBehavior.quack ();
}
public void performFly(){
flyBehavior.fly();
}
public void setFlyBehavior(FlyBehavior fb){
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb){
quackBehavior = qb;
}
public abstract void display ();
}
public interface FlyBehavior{
void fly();
}
public class FlyWithWings{
public void fly(){
Debug.Log ("FlyWithWingss");
}
}
public class FlyNoWay{
public void fly(){
Debug.Log ("FlyNoWay");
}
}
public interface QuackBehavior{
void quack();
}
public class Quack : QuackBehavior{
public void quack(){
Debug.Log("gugu~~");
}
}
public class Squack : QuackBehavior{
public void quack(){
Debug.Log("zhizhi");
}
}
public class MuteQuack : QuackBehavior{
public void quack(){
Debug.Log("Mute Quack");
}
}
public class MallardDuck : Duck{
public MallardDuck(){
flyBehavior = new FlyWithWings ();
quackBehavior = new Quack ();
}
public override void display(){
Debug.Log("MallardDuck display");
}
}
public class RedheadDuck : Duck{
public override void display(){
Debug.Log("RedheadDuck display");
}
}
1.封装变化
如果发现每次新的需求依赖。都会使某方面的代码发生改变,那么可以确定,这部分的代码需要被取出来,和其他稳定的代码有所区分。(例子中取出了鸭子的行为,并用 封装为行为接口)
2.多用组合(有一个),少用继承(是一个)
本例中,如果将鸭子的行为使用继承 赋予 鸭子具体类的话, 那么被继承的行为就固定下来了, 无法动态改变(可以看做是针对实现编程,失去灵活性)
而实际上,本例采用组合的方式,即鸭子类拥有 行为的接口实例, 并且鸭子拥有了“运行时动态改变行为”的可能性。
所以组合带给我们的好处应该是:灵活,动态改变
3.针对接口编程,而不是针对实现编程
针对实现编程: Dog d = new Dog;
针对接口/超类型编程: Animal animal = new Dog();
针对超类型编程,可以动态的改变行为(animal)
策略模式 定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。