策略模式,顾名思意,针对不同的要求采用不同的策略处理问题。
实际的“策略”通常都是算法簇,处理同一个问题或者执行同一动作可能有多种策略,而这些策略之间的切换如果以硬编码的方式写在代码中,则相当丑陋,策略模式提供了策略切换的一个动态的机制,即可以运行时指定。
比如,现在有一个关于鸭子系统,有一个抽象父类Duck, 里面声明了几个鸭子的动作,如 叫、飞、游泳、展示(在这里鸭子动作即是算法簇),针对这个抽象类有多种继承的子类,如MallarDuck(绿头鸭)、RedheadDuck(红头鸭)、RubberDuck(橡胶鸭), 现在问题出来了:并不是每种鸭子都会飞,例子橡胶鸭;每种鸭子的叫声可能并不一样;后一个问题可以通过在子类中重写“叫”这个方法来解决,但前一个问题并不能解决,因为继承是代码复用,导致每种鸭子都包含“飞”这个动作。为了解决这个问题,试将“飞”这个动作从Duck抽象类中分离出去,抽象成一个Flyable接口,需要“飞”这个动作的鸭子则实现这个接口,不需要的不实现这个接口~~表面上好像解决了问题,实现严重破坏了代码复用。因为接口只声明方法,并无实现,这样每种鸭的实现类中都必须重写“飞”这个方法,即使这个实现方式可能是完全一样的,更大的问题在于,如果以后要修改“飞”这个方法,又不得不到每个鸭实现中去一个一个的修改“飞”方法,这显然很不灵活。
软件设计的基本原则:
一、找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
二、针对接口编程,而不是针对实现编程。
三、多用组合,少用继承。
显然“飞”和“叫”这两个方法是Duck类中变化的部分(假如其他方法都是通用的),运用第一个原则,将它们两个都分离出来,分离成什么呢? 运用第二个原则可得出结论,分离成接口。
//飞
public interface FlyBehavior {
void fly();
}
//叫
public interface QuackBehavior {
void quack();
}
然后是具体的策略,分别实现这两个接口:
//不会飞
public class FlyNoWay implements FlyBehavior{
public void fly(){
System.out.println("Can't fly!");
}
}
//用翅膀飞
public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("fly with wings!");
}
}
//呱呱叫
public class QuackGuagua implements QuackBehavior {
public void quack() {
System.out.println("呱呱叫");
}
}
//不会叫
public class QuackNoWay implements QuackBehavior {
@Override
public void quack() {
System.out.println("不会叫...");
}
}
//吱吱叫
public class QuackZhizhi implements QuackBehavior {
@Override
public void quack() {
System.out.println("吱吱叫!");
}
}
客户需要使用策略,这里遵循第三条原则,我们采用组合的方式,在Duck中添加这两个接口的引用,分别在performQuack()和performFly()方法中使用上述接口的引用,调用“叫”动用和“飞”动作,同时声明两个set方法,用来动态的设置这两个引用的运行时对象:
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
public void swim(){
System.out.println("我在游泳...");
}
public abstract void display();
public void performQuack(){
quackBehavior.quack();
}
public void performFly(){
flyBehavior.fly();
}
}
测试:
public class Main {
public static void main(String[] args) {
Duck duck1 = new MallarDuck();
//动态设置策略
duck1.setFlyBehavior(new FlyWithWings());
duck1.setQuackBehavior(new QuackZhizhi());
duck1.display();
duck1.performFly();
duck1.performQuack();
System.out.println();
Duck duck2 = new RubberDuck();
//动态设置策略
duck2.setFlyBehavior(new FlyNoWay());
duck2.setQuackBehavior(new QuackGuagua());
duck2.display();
duck2.performFly();
duck2.performQuack();
}
}
总结:
策略模式的关键在于:分离变化部分、面向接口编程、包含策略接口类型引用变量、运行时动态确定具体策略对象
分享到:
相关推荐
策略模式是设计模式中的一种 객체行为型模式,它定义了一系列算法,封装每一个算法,并使它们可以互相替换。策略模式使得算法可以独立于使用它的客户而变化。 概述 在软件开发中,经常遇到类似的情况,实现某一个...
《白话设计模式》文档很可能是以通俗易懂的方式介绍设计模式的入门读物。 在软件开发过程中,设计模式可以帮助我们更有效地组织代码,提高代码的可读性和可维护性。设计模式通常分为三类:创建型、结构型和行为型...
14. 策略模式:定义了一系列算法,并将每个算法封装起来,使它们可以互相替换,策略对象改变算法的行为,如不同的损失函数或激活函数。 15. 命令模式:将请求封装为一个对象,以便使用不同的请求、队列请求、记录...
《白话C++》是一本非常...通过学习《白话C++》,你可以掌握这些基础知识,并逐渐进阶到更高级的主题,如设计模式、并发编程、模板元编程等。这将为你的编程生涯打下坚实的基础,并开启探索C++这一强大语言的广阔天地。
例如,工厂模式、单例模式、建造者模式属于创建型,适配器模式、装饰器模式属于结构型,而观察者模式、策略模式属于行为型。理解并熟练应用设计模式可以提高代码的可读性、可维护性和可扩展性。 2. **C++Templates....
文言文白话翻译参考书的普及使得教师面临教学挑战,教学质量并未因此提高。现有研究多集中于个别问题,缺乏全面性和系统性。 四、研究内容与实施方案 研究目标是构建一套适应农村初级中学实际的文言文教学策略,...
MVC模式是一种常见的软件设计模式,常用于Web开发,它将业务逻辑(Model)、用户界面(View)和数据控制(Controller)分离开来,使得代码更易于维护和扩展。 描述中提到“PHP程序设计,Web系统源码,数据库MySQL”...
- 应用策略模式来封装算法,使代码更灵活和可扩展。 9. **命名空间**: - 使用命名空间避免全局作用域中的名字冲突。 - 使用`using namespace`需谨慎,以防止引入不必要的命名冲突。 10. **C++11及以后的更新**...
5. 设计模式:代码中可能会体现出一些常见的设计模式,如工厂模式、观察者模式等,显示了编程的规范化和灵活性。 6. 数据处理:如果项目涉及数据,那么数据的读取、清洗、分析和展示的代码将揭示团队的数据处理能力...
3. **模型-视图-控制器(MVC)模式**:这种设计模式在Web应用中广泛使用,它分离了应用程序的数据层、业务逻辑层和用户界面层。模型负责数据处理,视图负责展示数据,而控制器负责协调模型和视图的交互。 4. **用户...
这些攻击可能包括追踪用户行踪、重建个人活动模式,甚至通过关联分析来推断敏感信息。了解这些模型可以帮助我们设计更安全的系统。 **第四部分:隐私意识的位置查询处理** 在处理位置查询时,应考虑用户隐私,例如...
在源码参考中,"lern_2"可能包含了实际的游戏AI训练代码,通过分析这些代码,可以学习到如何设计网络结构、定义环境模型、训练过程以及如何评估模型性能。此外,对于初学者来说,理解代码中的损失函数、优化器选择、...
Kafka 主要被设计用来处理大规模的实时数据流,它以其高性能、高可扩展性和强大的生态系统兼容性而受到赞誉。Kafka 使用 Scala 和 Java 编写,允许每秒处理数百万条消息,使其在大数据和流计算领域中独树一帜。 ...
此外,遵循MVC(模型-视图-控制器)或MVVM(模型-视图-ViewModel)设计模式,可以更好地组织代码结构,使组件易于复用和扩展。 7. **测试与调试** 对于这样一个组件,充分的测试是必不可少的。使用Qt的测试框架如...
9. **设计模式**:良好的编程实践中,可能采用了如MVC(模型-视图-控制器)或MVVM(模型-视图-视图模型)设计模式,以清晰地划分业务逻辑、界面显示和用户交互。 10. **错误处理**:为了保证程序的健壮性,应包含...
MVC(Model-View-Controller)是软件设计模式,将业务逻辑、数据展示和用户交互分离。在ThinkPHP框架下,Model层处理数据模型,View层负责显示视图,Controller层控制业务逻辑,这种分层设计有利于代码的复用和维护...
为了处理大规模的图数据,我们需要设计有效的算法,这包括采样技术,以便在不牺牲太多信息的情况下研究网络的代表性部分。同时,开发能高效处理大量边和顶点的计算策略是数据科学家的重要任务,以应对大数据时代的...
该设计的核心目标是通过局部二值模式(Local Binary Patterns, LBP)特征提取与深度学习模型的结合,实现高效且准确的人脸识别系统。 局部二值模式(LBP)是一种简单但有效的纹理描述符,常用于图像分析,特别是...
参数服务器是一种分布式系统的设计模式,常用于大规模机器学习任务,它将模型参数存储在一组服务器上,使得多台工作节点可以并行地更新模型。 在描述中提到的“深度学习使用技巧和一些模型训练”,意味着包含的资料...