1、前言
在之前的文章 C++优化if-else-if结构(一) 中介绍了一些关于优化代码中过多if-else-if结构的情况;采用上述的方式是能够进行一定程度的优化,但上述方法并没有采用面向对象的设计方式(OOD)。
上述代码暴违背了面向对象的设计中要求的设计原则:
(1)、单一职责原则:对类来说,一个类应该只负责一项职责;
在上述类的设计中,类 advNumSequence 包含了比较多的职责,比如说 adv_func1、adv_func2、adv_func3等。
(2)、依赖倒置原则:依赖倒置的中心思想是面向接口编程(或者说面向抽象编程);
在上述类的设计中,根本就没考虑面向接口编程。
(3)、开闭原则(OCP):OCP是编程中最基础、最重要的设计原则,它表明类的设计应该对扩展开放,对修改关闭;
在上述类的设计中,如果想要添加新的功能,就只能修改类 advNumSequence 了,显然是违背了 OCP原则。
2、OOD的设计方式
有如下问题:现有不同的动物,每种动物的行走方式和叫声都不一样,请你进行设计,显示不同动物的信息。
最容易想到的做法如下图所示:
使用时的伪代码如下所示:
void ShowAnimalInfo(Animal * pAnimal){
if pAnimal->type() is "Tiger":
pAnimal->Walk();
pAnimal->Roal();
else if pAnimal->type() is "Frog":
pAnimal->Jump();
pAnimal->Quack();
else if pAnimal->type() is "Snake":
pAnimal->Crawl();
pAnimal->Hiss();
else:
...
}
在上述伪代码中中,虽然已经实现了面向接口编程,但是在函数体内,还是要根据if-else-if结构来判断动物类别,并根据不同的类型,来显示不同的信息,这种做法显示仍然是不满足OCP原则的。下面接介绍一个采用设计模式来优化的方法。关于设计模式的概念在此就不多做描述。
3、策略模式
关于“策略模式”,在《设计模式(GOF)》书中的解释如下:
意图(Intent): 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。
原理类图:
参与者说明:
Strategy: 策略,
- 定义所有支持的算法的公共接口,Context 使用这个接口来调用某 ConcreteStrategy 定义的算法;
ConcreteStrategy: 具体策略,
- 以Strategy为接口实现某种具体算法;
Context: 环境上下文,
- 用一个ConcretetStrategy对象来配置;
- 维护一个对Strategy对象的引用;
- 可定义一个接口来让Strategy访问它的数据;
适用场景:
主要适用于以下场景:
- 许多相关的类仅仅是行为有异。“策略”提供了一种用于多个行为中的一个行为来配置一个类的方法;
- 需要使用一个算法的不同变体;
- 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构;
- 一个类定义了多种行为,并且这些行为在这个类的操作中以 多个条件语句 的形式出现;
注意事项和细节:
4、使用策略模式进行优化
采用策略模式对类进行重新设计,如下所示:
实现代码如下所示:
MoveBehavior:
class MoveBehavior
{
public:
virtual void Move() = 0;
};
class WalkBehavior: public MoveBehavior{
public:
void Move(){ cout << "is walk, "; }
};
class JumpBehavior: public MoveBehavior{
public:
void Move(){ cout << "is jump, "; }
};
class CrawlBehavior: public MoveBehavior{
public:
void Move(){ cout << "is crawl, "; }
};
CallBehavior:
class CallBehavior {
public:
virtual void Call() = 0;
};
class RoarBehavior: public CallBehavior{
public:
void Call(){ cout << "is roar " << endl; }
};
class QuackBehavior: public CallBehavior{
public:
void Call(){ cout << "is quack " << endl; }
};
class HissBehavior: public CallBehavior{
public:
void Call(){ cout << "is hiss " << endl; }
};
Animal:
class Animal{
public:
virtual void Show() = 0;
};
class Tiger : public Animal{
public:
Tiger(MoveBehavior* move, CallBehavior *call) : move(move), call(call)
{}
void Show(){
cout << "Tiger :";
move->Move();
call->Call();
}
private:
MoveBehavior *move;
CallBehavior *call;
};
class Frog : public Animal{
public:
Frog(MoveBehavior* move, CallBehavior *call) : move(move), call(call)
{}
void Show(){
cout << "Frog :";
move->Move();
call->Call();
}
private:
MoveBehavior *move;
CallBehavior *call;
};
Context:
class Context{
public:
void setAnimal(Animal * animal){ mp_animal = animal; }
void op(){ mp_animal->Show(); }
private:
Animal * mp_animal;
};
main:
void main()
{
//
Context *con = new Context;
//创建Tiger
WalkBehavior *walk1 = new WalkBehavior;
RoarBehavior *roar1 = new RoarBehavior;
Tiger *tiger = new Tiger(walk1, roar1);
con->setAnimal(tiger);
con->op();
//创建Frog
JumpBehavior *jump1 = new JumpBehavior;
QuackBehavior *quack1 = new QuackBehavior;
Frog *frog = new Frog(jump1, quack1);
con->setAnimal(frog);
con->op();
delete tiger; delete roar1; delete walk1;
delete frog ; delete quack1 ; delete jump1 ;
delete con;
return;
}
运行结果如下所示:
此时如果想要添加一个新的Animal对象,只需要添加如下代码(允许扩展)即可:
//定义Snake对象
class Snake : public Animal{
public:
Snake(MoveBehavior* move, CallBehavior *call) : move(move), call(call)
{}
void Show(){
cout << "Snake :";
move->Move();
call->Call();
}
private:
MoveBehavior *move;
CallBehavior *call;
};
//创建Snake
CrawlBehavior *crawl1 = new CrawlBehavior;
HissBehavior *hiss1 = new HissBehavior;
Snake *snake = new Snake(crawl1, hiss1);
con->setAnimal(snake);
con->op();
运行结果