zoukankan      html  css  js  c++  java
  • 设计模式之策略模式

     

    定义

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

    设计原则

    • 1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
    • 2.针对接口编程,而不是针对实现编程。
    • 3.多用组合,少用继承:下面的例子中,将两个类结合起来,就是组合,将适当的行为对象组合起来使用。使用组合建立系统具有很大的弹性。

    示例

    现在有一些鸭子,它们有木头鸭、橡胶鸭、真鸭等,我们需要设计一段代码来表示它们。

    第一次设计(使用OO)

    在父类中加上fiy()就会导致所有的子类都具有此方法,但有的子类并不需要此方法。
    缺点:需要覆盖不同实现的代码

    第二次设计(使用接口)

    所有的子类方法都从不同的接口实现,但会导致需要实现许多重复的代码。
    缺点:代码无法复用
    这里最好可以建立一种软件的方法,好让我们可以用一种对既有的代码影响最小的方式来修改软件。

    第一次改进(封装变化)

    根据设计原则一:

    第二次改进(针对接口编程)

    根据第二原则:

    这里使用接口表示每个行为,而实际的现象不会被绑定在子类中,这样做可以让飞行动作被其他对象复用,因为这些行为已经与鸭子类无关了。
    针对接口编程,关键在于多态。程序可以针对父类编程,在执行时会根据实际状况执行真正的行为,不会被绑死在父类的行为上。
    针对父类编程:变量的声明类型应该时父类,通常可以是一个抽象类或者是一个接口,如此,只要实现此父类的类所产生的对象,都可以指定给这个变量,这也就意味着,声明类时不用理会以后执行时的真正对象类型!

    做法:

    针对实现编程:
    声明变量为dog类型,针对具体实现编码
    Dog d=new Dog();
    d.bark();
    针对接口/父类编程:
    我们知道对象是dog,但是利用Animal 进行多态调用
    Animal animal=new Dog();
    animal.makeSound()
    运行时才指定具体实现对象:
    我们不知道它的子类型,我们只需要知道它能正确的进行makeSound就可以了
    a=getAnimal();
    a.makeSound();

    实现鸭子的行为

    实现父类Duck:

    public abstract class Duck
    {
    public QuackBehavior quackbehavior;//引用实现QuackBehavior的接口对象
    public FlyBehavior flyBehavior;
    public Duck()
    {
    }
    public abstract void display();
    public void PerformFly()
    {
    flyBehavior.Fly();//委托给行为类
    }
    public void PerformQuack()
    {
    quackbehavior.Quack();//委托给quackbehavior对象实现Quack
    }
    public void swim()
    {
    Console.WriteLine("All ducks float,even decoys!");
    }
    }

    飞行行为接口:

    public interface FlyBehavior//所有飞行类都必须实现接口
    {
    void Fly();
    }

    不能飞行行为对飞行接口实现:

    public class FlyNoWay : FlyBehavior
    {
    public void Fly()//飞行实现,给不能飞的使用
    {
    Console.WriteLine("I can‘t fly");
    }
    }

    能飞行行为对飞行接口实现:

    public class FlyWithWings : FlyBehavior
    {
    public void Fly()//飞行实现,给可以飞的使用
    {
    Console.WriteLine("I’m flying!!");
    }
    }

    叫声行为接口:

    public interface QuackBehavior
    {
    void Quack();
    }

    三种叫声行为的接口实现:

    public class Quack : QuackBehavior
    {
    void QuackBehavior.Quack()
    {
    Console.WriteLine("Quack");
    }
    }
    
    public class MuteQuack : QuackBehavior
    {
    void QuackBehavior.Quack()
    {
    Console.WriteLine("MuteQuack");
    }
    }
    
    public class Squeak : QuackBehavior
    {
    void QuackBehavior.Quack()
    {
    Console.WriteLine("Squeak");
    }
    }

    MallardDuck对象类实现:

    class MallardDuck:Duck
    {
    public MallardDuck()
    {
    quackbehavior = new Quack();//当PerformQuack()被调用时,职责被委托给了Quack()
    flyBehavior = new FlyWithWings();//FlyWithWings作为FlyBehavior类型
    }
    
    public override void display()
    {
    Console.WriteLine("I'm a real Mallard duck!");
    }
    }

    RubberDuck对象类实现:

    public class RubberDuck : Duck
    {
    public RubberDuck()
    {
    quackbehavior = new MuteQuack();
    flyBehavior = new FlyNoWay();
    }
    
    public override void display()
    {
    Console.WriteLine("I'm a real Rubber duck!");
    }
    }

    测试:

    static void Main(string[] args)
    {
    Duck mallard = new MallardDuck();
    mallard.PerformQuack();
    mallard.PerformFly();
    
    Duck rubberDuck=new RubberDuck();
    rubberDuck.PerformQuack();
    rubberDuck.PerformFly();
    Console.ReadKey();
    }

    动态设定行为

    在Duck类中加入两个新方法:

    public void setFlyBehavior(FlyBehavior fb)
    {
    flyBehavior = fb;
    }
    
    public void SetQuackBehavior(QuackBehavior qb)
    {
    quackbehavior = qb;
    }

    新鸭子类型ModelDuck:

    class MallardDuck:Duck
    {
    public MallardDuck()
    {
    quackbehavior = new Quack();//当PerformQuack()被调用时,职责被委托给了Quack()
    flyBehavior = new FlyWithWings();//FlyWithWings作为FlyBehavior类型
    }
    
    public override void display()
    {
    Console.WriteLine("I'm a real Mallard duck!");
    }
    }

    建立一个新的飞行行为FlyBehavior:

    public class FlyRocketPowered : FlyBehavior
    {
    public void Fly()
    {
    Console.WriteLine("I'm flying with a rocket!");
    }
    }

    测试:

    static void Main(string[] args)
    {
    MoveSetBehavior.Duck modelDuck = new ModelDuck();
    modelDuck.PerformFly();
    modelDuck.setFlyBehavior(new FlyRocketPowered());
    modelDuck.PerformFly();
    
    
    Console.ReadKey();
    }

    总结

    现在我们在回到文章最开始来看看策略模式的定义:策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。所以我们可以把鸭子的每组行为当作是一个算法族,而里面每个具体的行为则是算法。

  • 相关阅读:
    Windows Server 2008 下解析二级域名的方法
    浅谈2D游戏设计模式--游戏剧情设计(1)
    公司做项目的几点经验总结(个人经验)
    ASP.NET 实现站内信功能(点对点发送,管理员群发)
    FusionChart 水印破解方法(代码版)
    如何使用SOIL在VS2012的 C++环境下显示图片
    C语言实现控制台中光标随意移动
    ASP.NET CMS模板培训教程
    如何用easyui+JAVA 实现动态拼凑datagrid表格(续)
    用JAVA实现插值查询的方法(算近似值,区间求法)
  • 原文地址:https://www.cnblogs.com/Tan-sir/p/8107958.html
Copyright © 2011-2022 走看看