zoukankan      html  css  js  c++  java
  • 设计模式笔记——策略模式(Strategy Pattern)

    一、概述

    策略模式:定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法变化独立于使用算法客户。

    --摘自《Head First设计模式》

    二、策略模式:

    我们用《Head First设计模式》一书中的例子分析一下为什么我们采用策略模式解决问题。

    现在我们要开发一个鸭子的游戏,开始鸭子有游泳,叫,玩等行为。

    我们用继承和多态来实现不同的鸭子执行不同的行为,在我们遇到一个问题,每增加一个类型的鸭子我们都需要重写类型内部发方法,最后发现很多重复代码。

    这时,你的老板不高兴了,需要你做优化处理,首先我们考虑到接口:

    但是接口实现过程中同样有过多的重复代码出现,没有从根本上解决代码堆积的问题。

    这时策略模式就派上用场了,看一下类图:

     

     显而易见,我们把可变的行为以接口继承的方式实现,行为接口与Duck类以组合形式存在。

     

    三. 源码实现:

    1. 飞行行为:

        public interface FlyBehavior
        {
            string Fly();
        }
    
        public class FlyWithWing:FlyBehavior
        {
            public string Fly()
            {
                return string.Format("I am flying!");
            }
        }
    
        public class FlyNoWay:FlyBehavior
        {
            public string Fly() 
            {
                return string.Format("I Can't fly!");
            }
        }
    
        public class FlyRocketPowered:FlyBehavior
        {
            public string Fly()
            {
                return string.Format("I'm flying with a rocket!");
            }
        }

    2. 鸭叫行为:

        public interface QuackBehavior
        {
            string quack();
        }
    
        public class Quack:QuackBehavior
        {
            public string quack()
            {
                return string.Format("Quack!");
            }
        }
    
        public class SQuack:QuackBehavior
        {
            public string quack()
            {
                return string.Format("SQuack!");
            }
        }
    
        public class MuteQuack:QuackBehavior
        {
            public string quack()
            {
                return string.Format("MuteQuack!");
            }
        }


    3. 鸭子基类:

    public abstract class Duck
    {
        protected FlyBehavior flyBehavior;
        protected QuackBehavior quackBehavior;
    
        public abstract string Display();
    
        public string PerformFly()
        {
            return flyBehavior.Fly();
        }
    
        public string PerformQuack()
        {
            return quackBehavior.quack();
        }
    
        public void SetFlyBehavior(FlyBehavior flyBehavior)
        {
            this.flyBehavior = flyBehavior;
        }
    
        public void SetQuackBehavior(QuackBehavior quackBehavior)
        {
            this.quackBehavior = quackBehavior;
        }
    
        public string Swim()
        {
            return string.Format("I'm Swimming!");
        }
    }

    4.鸭子子类:

    public class MallardDuck:Duck
    {
        public MallardDuck()
        {
            flyBehavior = new FlyWithWing();
            quackBehavior = new Quack();
        }
        public override string Display()
        {
            return string.Format("I'm a real duck!");
        }
    }
    
    public class ModelDuck:Duck
    {
        public ModelDuck()
        {
            flyBehavior = new FlyNoWay();
            quackBehavior = new MuteQuack();
        }
        public override string Display()
        {
            return string.Format("I'm a model duck!");
        }
    }

    5.测试实现:

    [TestClass]
    public class MallardDuckTest
    {
        [TestMethod]
        public void MallardDuckBehavior()
        {
            string expected = "Quack!";
            Duck mallardDuck = new MallardDuck();
            string actual= mallardDuck.PerformQuack();
            Assert.AreEqual(expected,actual);
    
            expected = "I am flying!";
            actual = mallardDuck.PerformFly();
            Assert.AreEqual(expected, actual);
    
            expected = "I'm flying with a rocket!";
            mallardDuck.SetFlyBehavior(new FlyRocketPowered());
            actual = mallardDuck.PerformFly();
            Assert.AreEqual(expected, actual);
        }
    }

    四. 总结

    我们用策略模式解决了那些问题:

    1.代码在子类中的重复问题。

    2.运行时行为不容易改变。

    3.很难知道所有鸭子的行为。

    4. 改变会牵一发而东全身,造成其他鸭子不想要的改变问题。

    我们回顾一下OO的重要原则:

    1. 封装变化。

    2. 多用组合,少用继承。

    3. 针对接口编程,不针对实现编程。

     

  • 相关阅读:
    【软件工程Ⅱ】作业二 |分布式版本控制系统Git的安装与使用
    【软件工程Ⅱ】作业一 |走进计算机
    字符串、文件操作,英文词频统计预处理
    了解大数据的特点、来源与数据呈现方式
    作业五:结对项目-“四则运算”之升级版
    第四次作业:小学四则运算“软件”之初版
    阅读《构建之法》1-5章的感想
    作业二/Git的安装以及使用
    大三学习软件工程感想
    爬取全部的校园新闻
  • 原文地址:https://www.cnblogs.com/Abel-Zhang/p/StrategyPattern.html
Copyright © 2011-2022 走看看