策略模式
软件领域中的设计模式的重要性不言而喻。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态。虽然知道这些特性的定义但是并没有做到真正的理解,这样特性有什么作用?用于什么场合中等等问题,带着疑问开始学习设计模式,主要参考《大话设计模式》和《设计模式:可复用面向对象软件的基础》两本书。
简单工厂缺点,每次增加相应子类,都要维护或者扩展这个工厂,以致代码需要重新编译部署,这是比较糟糕的处理方式,所以不是最好的处理方法,面对算法的时常变动应该有更好的方法,这就是我们将要介绍的设计模式之一:策略模式
策略模式定义了算法家族,分别封装起来,他们之间可以互相替换,此模式让算法的变化,不会影响使用算法的客户,例如商场收银系统应该考虑策略模式
面向对象的编程不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性的功能的对象的抽象集合才是类。
优点:适合类中的成员以方法为主,算法经常变动;简化了单元测试(因为每个算法都有自己的类,可以通过自己的接口单独测试。
策略模式和简单工厂基本相同,但简单工厂模式只能解决对象创建问题,对于经常变动的算法应使用策略模式。
缺点:客户端要做出判断。
简单工厂和策略模式的区别:
策略模式是客户端要做出判断,生成相应的抽象基类子类对象,然后调用策略类中的函数,策略类中包含抽象基类和相应的接口函数。简单工厂模式判断条件是在工厂中判断,然后生成基类相对应对象,调用该对象方法,
例子:输入两个数可操作符,输出结果;策略模式的结果如下:#include
#include
using namespace std;
//基类
class COperation
{
public:
int m_nFirst;
int m_nSecond;
virtual double GetResult()
{
double dResult = 0;
return dResult;
}
};
//加法
class AddOperation : public COperation
{
public:
AddOperation(int a, int b)
{
m_nFirst = a;
m_nSecond = b;
}
double GetResult() override
{
return m_nFirst + m_nSecond;
}
};
//减法
class SubOperation : public COperation
{
public:
SubOperation(int a, int b)
{
m_nFirst = a;
m_nSecond = b;
}
double GetResult() override
{
return m_nFirst - m_nSecond;
}
};
//乘法
class MulOperation : public COperation
{
public:
MulOperation(int a, int b)
{
m_nFirst = a;
m_nSecond = b;
}
double GetResult() override
{
return m_nFirst * m_nSecond;
}
};
//除法
class DivOperation : public COperation
{
public:
DivOperation(int a, int b)
{
m_nFirst = a;
m_nSecond = b;
}
double GetResult() override
{
return m_nFirst / m_nSecond;
}
};
//策略类
class Context
{
private:
COperation *lhs;
public:
Context(){}
Context(COperation *rhs)
{
lhs = rhs;
}
double Result()
{
return lhs->GetResult();
}
};
//客户端
int main()
{
int a, b;
char oper;
cout << "请输入numberA: ";
cin >> a;
cout << "请输入运算符: ";
cin >> oper;
cout << "请输入numberB: ";
cin >> b;
Context cs;
switch (oper)
{
case '+':
cs = Context(new AddOperation(a,b));
break;
case '-':
cs = Context(new SubOperation(a, b));
break;
case '*':
cs = Context(new MulOperation(a, b));
break;
case '/':
cs = Context(new DivOperation(a, b));
break;
default:
cout << "输入有误";
break;
}
cout << "运算结果是:" << cs.Result() << endl;
return 0;
}
例子:输入两个数可操作符,输出结果;策略模式和简单工厂结合的结果如下:
//简单工厂和策略模式结合
#include
#include
using namespace std;
//基类
class COperation
{
public:
int m_nFirst;
int m_nSecond;
virtual double GetResult()
{
double dResult = 0;
return dResult;
}
};
//加法
class AddOperation : public COperation
{
public:
AddOperation(){}
AddOperation(int a, int b)
{
m_nFirst = a;
m_nSecond = b;
}
double GetResult() override
{
return m_nFirst + m_nSecond;
}
};
//减法
class SubOperation : public COperation
{
public:
SubOperation(){}
SubOperation(int a, int b)
{
m_nFirst = a;
m_nSecond = b;
}
double GetResult() override
{
return m_nFirst - m_nSecond;
}
};
//乘法
class MulOperation : public COperation
{
public:
MulOperation(){}
MulOperation(int a, int b)
{
m_nFirst = a;
m_nSecond = b;
}
double GetResult() override
{
return m_nFirst * m_nSecond;
}
};
//除法
class DivOperation : public COperation
{
public:
DivOperation(){}
DivOperation(int a, int b)
{
m_nFirst = a;
m_nSecond = b;
}
double GetResult() override
{
return m_nFirst / m_nSecond;
}
};
//策略类和简单工厂结合
class Context
{
private:
COperation *lhs=nullptr;
public:
Context(){}
Context(int a ,int b,const char oper)
{
switch (oper)
{
case '+':
lhs =new AddOperation(a,b);
break;
case '-':
lhs = new SubOperation(a, b);
break;
case '*':
lhs = new MulOperation(a, b);
break;
case '/':
lhs = new DivOperation(a, b);
break;
default:
cout << "输入有误";
break;
}
}
double Result()
{
return lhs->GetResult();
}
};
//客户端
int main()
{
int a, b;
char oper;
cout << "请输入numberA: ";
cin >> a;
cout << "请输入运算符: ";
cin >> oper;
cout << "请输入numberB: ";
cin >> b;
Context cs(a,b,oper);
cout << "运算结果是:" << cs.Result() << endl;
return 0;
}
可以看到在客户端中,策略模式需要认识的类共有5个,在简单工厂实例博客一文中,客户端需要认识的类有两个。但是我们将简单工厂和策略模式相结合可以看到客户端需要知道的类为1个。这使得耦合性降低,结合的方法使得客户直接有内部的算法隔离。
总结:
1、策略模式是一种定义一系列算法的方法,从概念上来说,所有这些方法完成的都是完成相同的工作,只是实现不同,他可以以相同的方式调用所有的算法,减少各种算法类之间的耦合性。
2、策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或者行为,继承有助于析取出这些算法中的公共功能,例子中的公共功能是Result();
3、策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
4、策略模式的缺点是,选择所用具体实现的职责有客户端对象承担,然后传给Context对象,这样对客户有一定的选择压力,但是我们可以将简单工厂和策略模式结合,来解决这个问题。
5、当然结合的这种方式也有一定的缺点,每档增加一种算法时,在增加算法子类的同时,还要修改Context中的Switch语句块,解决这种的办法是(反射??),带着问题进一步的学习。