美文网首页
1.策略模式

1.策略模式

作者: 你今天作业做了吗 | 来源:发表于2019-03-24 18:16 被阅读0次

    模拟鸭子应用

    需求

    • 游戏中会出现各种鸭子,一边游泳戏水,一边呱呱叫。

    一开始,是通过使用继承的方式,用派生类实现各种鸭子。

    class Duck {
    public:
        void quack();
        void swim();
        void display();
    };
    
    class MallardDuck : Duck {
    public:
        void display() {
            // 外观是绿头
        }
    };
    
    class RedheadDuck {
        void display() {
            // 外观是红头
        }
    };
    

    以上缺点:

    • 代码在多个子类中重复;
    • 运行时的行为不容易改变;
    • 我们不能让鸭子跳舞;
    • 很难知道所有鸭子的全部行为;
    • 鸭子不能同是又飞又叫;
    • 改变会牵一发动全身,造成其他鸭子不想要的改变。

    由于需求总在变化,现在我们需要让鸭子能飞起来。不同的鸭子,叫声、显示、飞行方式都可能不太一样。

    面对这种情况,我们需要的是将不变的部分放在基类中,而将经常变化的部分分离出来,作为独立的部分进行封装。为此,我们做了以下工作:

    • 利用抽象类(接口)代表每个行为,比如说FlyBehavior和QuackBehavior,而行为的每个实现都将实现其中的一个抽象类。
    • 鸭子的子类将使用抽象类(FlyBehavior与QuackBehavior)所表示的行为,所以实际的“实现”不会被绑死在鸭子的子类中。
    • 此次使用的是组合方式,而不是继承的方式进行实现。

    于是代码变成了如下:

    
    // 定义飞行行为抽象类(接口),
    // 将鸭子类中经常变化的部分进行分离与封装。
    class FlyBehavior {
    public:
        virtual void fly() = 0;
        
        // 该类为基类,是需要被继承的。
        // 因此,析构函数需要被写成虚函数形式,
        // 这样子资源才得以正确释放。
        virtual ~FlyBehavior() {};
    };
    
    // 使用飞行行为抽象类(接口),
    // 实现用翅膀飞行的具体类,
    // 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
    class FlyWithWings : public FlyBehavior {
    public:
        virtual void fly() {
            cout << "Fly with wings." << endl;
        }
    };
    
    // 使用飞行行为抽象类(接口),
    // 实现没有飞行的具体类,
    // 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
    class FlyNoWay : public FlyBehavior {
    public:
        virtual void fly() {
            cout << "FlyNoWay: 啥时都不干。" << endl;
        }
    };
    
    // 定义鸭叫行为抽象类(接口),
    // 将鸭子类中经常变化的部分进行分离与封装。
    class QuackBehavior {
    public:
        virtual void quack() = 0;
        
        // 该类为基类,是需要被继承的。
        // 因此,析构函数需要被写成虚函数形式,
        // 这样子资源才得以正确释放。
        virtual ~QuackBehavior() {};
    };
    
    // 使用鸭叫行为抽象类(接口),
    // 实现鸭的呱呱叫具体类,
    // 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
    class Quack : public QuackBehavior {
    public:
        virtual void quack() {
            cout << "Quack quack..." << endl;
        }
    };
    
    // 使用鸭叫行为抽象类(接口),
    // 实现鸭的唧唧叫具体类,
    // 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
    class Squeak : public QuackBehavior {
    public:
        virtual void quack() {
            cout << "Squeak squeak..." << endl;
        }
    };
    
    // 使用鸭叫行为抽象类(接口),
    // 实现鸭的哑叫(不叫)具体类,
    // 为下面继承鸭子基类的派生类复用和灵活设定使用类而使用。
    class MuteQuack : public QuackBehavior {
    public:
        virtual void quack() {
            cout << "mute quack..." << endl;
        }
    };
    
    
    // 鸭子作为具体基类,为后面各种鸭子的派生类做基础。
    // 鸭子之所以作为基类而不是抽象类(接口),
    // 是因为鸭子本身有具体的部分。
    // 将鸭子的叫、飞行等方式通过组合的形式,而不是继承的方式实现,
    // 可以获得在运行中动态改变,也实现了代码的最大化复用。
    // 也不会出现引起继承所造成的牵一发动全身的缺点。
    // 将不变的部分封装在基类即可。
    class Duck {
    public:
        Duck() {
            quackBehavior = nullptr;
            flyBehavior = nullptr;
        }
    
        // 该类为基类,是需要被继承的。
        // 因此,析构函数需要被写成虚函数形式,
        // 这样子资源才得以正确释放。
        virtual ~Duck() {};
    
        // 将鸭叫行为委托给行为类实现,
        // 实现类中经常变化的部分分离,得以封装。
        // 也实现了将变化的代码最大化的复用与灵活性。
        void performQuack() {
            quackBehavior->quack();
        };
    
        // 将飞行行为委托给行为类实现,
        // 实现类中经常变化的部分分离,得以封装。
        // 也实现了将变化的代码最大化的复用与灵活性。
        void performFly() {
            flyBehavior->fly();
        };
    
        virtual void display() {
            cout << "Duck display" << endl;
        }
    
        // 获得该类的鸭叫行为类
        const QuackBehavior const* getQuackBehavior() {
            return quackBehavior;
        }
    
        // 获得该类的飞行行为类
        const FlyBehavior const* getFlyBehavior() {
            return flyBehavior;
        }
    
        // 设置该类的鸭叫行为类
        void setQuackBehavior(QuackBehavior* quack) {
            delete quackBehavior;
            quackBehavior = quack;
        }
    
        // 设置该类的飞行行为类
        void setFlyBehavior(FlyBehavior* fly) {
            delete flyBehavior;
            flyBehavior = fly;
        }
    
    // 类成员使用保护方式,将实现派生类可以访问该类成员,
    // 实现该类在具体运行过程中可以动态改变行为。
    protected:
        QuackBehavior* quackBehavior;
        FlyBehavior* flyBehavior;
    };
    
    class MallardDuck : public Duck {
    public:
        // 初始化派生类的行为类
        MallardDuck() {
            quackBehavior = new Quack;
            flyBehavior = new FlyWithWings;
        }
    
        // 释放派生类所拥有的资源
        virtual ~MallardDuck() {
            delete quackBehavior;
            delete flyBehavior;
        }
    
        // 实现派生类的显示
        virtual void display() {
            cout << "MallardDuck display..." << endl;
        }
    };
    
    class RedHeadDuck : public Duck {
    public:
        // 初始化派生类的行为类
        RedHeadDuck() {
            quackBehavior = new Squeak;
            flyBehavior = new FlyNoWay;
        }
    
        // 释放派生类所拥有的资源
        virtual ~RedHeadDuck() {
            delete quackBehavior;
            delete flyBehavior;
        }
    
        // 实现派生类的显示
        virtual void display() {
            cout << "RedHeadDuck display..." << endl;
        }
    };
    
    

    相关文章

      网友评论

          本文标题:1.策略模式

          本文链接:https://www.haomeiwen.com/subject/euauvqtx.html