示例问题:
对于应届毕业生找工作是去大公司还是去小公司的问题,网上有诸多说法。比如,管理制度和规章制度方面,小公司不是很健全,大公司比较健全;综合能力提升方面,小公司人少,要做的事多,对综合能力提升较快,大公司则专注某一个模块,综合能力锻炼不是太多,但可以把这个模块做精做细;职位上升方面,小公司人少,机会较多,而大公司由于人多,所以往上走就比较困难,同时公司让一个人去负责一个大项目的机会也很少。等等等
写一个程序描述上面情况,要考虑在去大公司还是小公司时,新增考虑因素时程序的扩展。
PS:上面问题只是一个示例,并不代表正确观点(去大小公司方面)。对于网上的关于去大小公司的说法,也请辩证理性看待。
分析:
如果将大公司和小公司作为两个类,考虑因素作为这两个类的属性,当属性(考虑因素)的值分别是“管理制度和规章制度方面”、“综合能力提升方面”、“职位上升方面”等时,输出特性。那这样的话,需要在判断属性值是什么,然后分别输出,需要在程序内有很多判断逻辑,且如果新增属性(考虑因素)的值时,需要改动代码。
解决方案:
Visitor.h
在该文件中,实现了考虑因素的基类IElement,及考虑因素的子类(考虑因素的具体内容)——CRegime(管理制度、规章制度)、CCapacity(综合能力)、CRose(职位上升)。公司基类ICompany,及其子类CBigCompany(大公司)、CSmallCompany(小公司)。通过ICompany的Accept接口,将IElement作为参数去访问ICompany,具体针对ICompany子类的处理有IElement的子类去做判断,这样实现了对公司考虑因素的多种情况的判断处理在外部进行。
#pragma once
#include <iostream>
#include <string>
//考虑因素基类
class IElement
{
public:
IElement()
{
}
virtual ~IElement()
{
}
virtual void PrintPigCompanySituation() = 0;
virtual void PrintSmallCompanySituation() = 0;
};
//公司基类
class ICompany
{
public:
ICompany()
{
}
virtual ~ICompany()
{
}
virtual void Accept(IElement* pVisitor) = 0;
};
//管理制度、规章制度
class CRegime : public IElement
{
public:
void PrintPigCompanySituation()
{
std::cout << "管理制度和规章制度方面:比较健全" << std::endl;
}
void PrintSmallCompanySituation()
{
std::cout << "管理制度和规章制度方面:不是很健全" << std::endl;
}
};
//综合能力
class CCapacity : public IElement
{
public:
void PrintPigCompanySituation()
{
std::cout << "综合能力方面:专注某一个模块,综合能力锻炼不是太多,但可以把这个模块做精做细" << std::endl;
}
void PrintSmallCompanySituation()
{
std::cout << "综合能力方面:人少,要做的事多,对综合能力提升较快" << std::endl;
}
};
//职位上升
class CRose : public IElement
{
public:
void PrintPigCompanySituation()
{
std::cout << "职位上升方面:由于人多,所以往上走就比较困难,同时公司让一个人去负责一个大项目的机会也很少" << std::endl;
}
void PrintSmallCompanySituation()
{
std::cout << "职位上升方面:人少,机会较多" << std::endl;
}
};
//大公司
class CBigCompany : public ICompany
{
public:
CBigCompany()
{
}
virtual ~CBigCompany()
{
}
void Accept(IElement* pVisitor)
{
if (nullptr != pVisitor)
{
pVisitor->PrintPigCompanySituation();
}
}
};
//小公司
class CSmallCompany : public ICompany
{
public:
CSmallCompany()
{
}
virtual ~CSmallCompany()
{
}
void Accept(IElement* pVisitor)
{
if (nullptr != pVisitor)
{
pVisitor->PrintSmallCompanySituation();
}
}
};
main.cpp
// main.cpp : Defines the entry point for the console application.
//
#include "Visitor.h"
int main()
{
CRegime* pRegime = new(std::nothrow) CRegime();
CCapacity* pCapacity = new(std::nothrow) CCapacity();
CRose* pRose = new(std::nothrow) CRose();
std::cout << "大公司的情况" << std::endl;
CBigCompany BigCompany;
BigCompany.Accept(pRegime);
BigCompany.Accept(pCapacity);
BigCompany.Accept(pRose);
std::cout << "小公司的情况" << std::endl;
CSmallCompany SmallCompany;
SmallCompany.Accept(pRegime);
SmallCompany.Accept(pCapacity);
SmallCompany.Accept(pRose);
if (nullptr != pRegime)
{
delete pRegime;
pRegime = nullptr;
}
if (nullptr != pCapacity)
{
delete pCapacity;
pCapacity = nullptr;
}
if (nullptr != pRose)
{
delete pRose;
pRose = nullptr;
}
system("pause");
return 0;
}
运行结果
访问者模式的使用:
访问者模式,表示一个作用于某对象结构中的各元素的操作。它是你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
访问者模式适用于数据结构相对稳定的系统。它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。
如上面例子,如果要新增办公环境这个考虑因素时,则值需要再实现办公环境基于IElement的子类,再客户调用的时候,调用公司类的Accept传入该对象指针即可,而不用再去修改公司类,符合开放-封闭原则。
何时使用访问者模式:
访问者模式的目的是要把处理从数据结构分离出来。很多系统可以按照算法和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易。
反之,如果这样的系统的数据结构对象易于变化,经常要有新的数据对象增加进来,就不适合使用访问者模式。
访问者模式的优点就是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。
访问者模式的缺点其实也就是使增加新的数据结构变得困难了。
返回目录:设计模式(C++实现)(总)