如何在运行时根据需求透明地更改对象的算法?将算法和对象本身解耦,从而避免上述问题?
我们假设现在有一个需求,需要对不同的颜色做不同的策略(算法)。
enum Color {
RED,
BLUE
};
class strategy {
private:
Color color;
public:
void strategy_func() {
if (color == RED) {
//do something
}
else if (color == BLUE) {
// do something else
}
}
};
以上是比较经典的做法,使用一个枚举类型来指定当前的颜色,对不同的颜色做不同的处理。
那么,如果需求改变了,新增了一个粉色,那么代码需要做如下更改
enum Color {
RED,
BLUE,
PINK //变化
};
class strategy {
private:
Color color;
public:
void strategy_func() {
if (color == RED) {
//do something
}
else if (color == BLUE) {
// do something else
}
else if (color == PINK) { //变化
// do sth with pink
}
}
};
这样的作法虽然可行,但是违背了开放封闭(OCP)的设计原则。也就是类模块是可扩展的,但是不要修改。
我们修改我们的类如下
class strategy {
public:
virtual void func() = 0;
virtual ~strategy(){}
};
class REDstrategy :public strategy {
virtual void func() {
// do something
}
};
class BLUEstrategy :public strategy {
virtual void func() {
// do something
}
};
class PINKstrategy :public strategy {
virtual void func() {
// do something
}
};
class solution {
private:
strategy* pointer;
public:
void solute() {
// ...
// 确认颜色
// 或者在构造函数中确认颜色
// 即pointer指针指向哪个子类
pointer->func();
//...
}
};
我们将对应不同颜色的方法,修改成从同一个基类中继承出来的子类。
在最后的solution中,使用基类的指针,使用多态思想来确认颜色和对应的处理方法,并调用。
这样在新的需求到达的时候,我们只需要新增一个继承出的子类并实现对应的算法即可。其他方法都不需要修改。(如何在solution过程中确定是否是新增的颜色,可以在构造函数中使用工厂设计模式)
定义一系列算法,将它们一个个封装起来,并且使它们可以相互替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。——《设计模式》
结合上面的代码理解模式的定义,互相替换也就是也就是PINKstrategy类的添加。独立于客户程序也就是solution类,保证了solution类的稳定,变化指多态地使用不同颜色子类的func()。
红色圈中的是稳定的部分,也就是对应以上的strategy和solution类。蓝色圈中的是变化的部分,也就是以上的对应各个颜色的子类。
运行时
多态的指针的子类方法就实现了运行时确定的需求。
并且,大段的if-else代码不用加载到内存中