设计模式之策略模式

 

正文

 

定义

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

设计原则

  • 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();
}
复制代码

总结

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

 

posted on   Mr.Tan&  阅读(633)  评论(2编辑  收藏  举报

编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南

导航

< 2025年3月 >
23 24 25 26 27 28 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 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示