如何为多企业场景优化Employee与Manager类的C++面向对象设计?
我定义了基类Employee及其子类Manager,Employee包含薪资、员工信息、绩效评估等相关成员与方法,Manager则扩展了团队管理、评估预算等功能,代码如下:
class Employee { string name, address, empId; int salary; Dept dept; public: void [Get/Set]Name(); void GetEmpid(); void SetSalary(); virtual void StartOnboarding(); virtual void startOfboarding(); virtual void startAppraisal(); }; class Manager : public Employee { list teamList; int appraisalBudget; public: int [Get/Set]AppraisaBudget(); int [Add/Delete]EmployeeInTeam(emp); void StartTeamAppraisal(); };
目前存在多家企业(Company1、Company2等,未来可能新增),不同企业的Employee和Manager虽保持Employee-Manager的继承关系,但部分方法的实现存在差异,例如Company1的Employee::StartOnboarding()与Company2的实现不同,Company1的Manager::StartTeamAppraisal()也与Company2的实现不同。
最初的设计方案是为每个企业创建专属的Employee子类(如EmployeeCompany1、EmployeeCompany2)和Manager子类(如ManagerCompany1、ManagerCompany2),其中Employee的企业子类重写相关虚方法,代码如下:
class EmployeeCompany1 : public Employee { int tasksDone; int clientsMeetingsDone; int appreciationsReceived public: // Company1 specific implementation of following virtual void StartOnboarding() { ... } virtual void startOfboarding() { ... } virtual void startAppraisal() { ... } }; class EmployeeCompany2 : public Employee { int bugSolved; int featureDeveloped; public: // Company2 specific implementation of following virtual void StartOnboarding() { ... } virtual void startOfboarding() { ... } virtual void startAppraisal() { ... } };
但该设计存在缺陷:Employee的企业子类与Manager同属Employee的子类,但二者行为层级不符;若为Manager创建企业子类,需同时继承对应企业的Employee子类和Manager基类,会引发多重继承问题,示例代码如下:
class ManagerCompany1 : public EmployeeCompany1, public Manager { protected: int company1specificData; public: virtual void StartTeamAppraisal() { // make use of data member of EmployeeCompany1 and other things specific to company1 } }; class ManagerCompany2 : public EmployeeCompany2, public Manager { protected: int company2specificData; public: virtual void StartTeamAppraisal() { // make use of data member of EmployeeCompany2 and other things specific to company2 } };
需求:
- 确认该场景是否为面向对象设计中的典型场景;
- 寻求适用于该场景的更优C++面向对象设计方案。
1. 场景确认
这是面向对象设计中典型的多维度变化场景:一类是角色维度(普通员工、经理),另一类是企业维度(不同公司的业务规则差异)。当两个维度都需要独立扩展时,最初的单继承方案会导致类爆炸,还会引入多重继承的菱形问题,属于典型的需要用设计模式解决的场景。
2. 优化设计方案
推荐使用**桥接模式(Bridge Pattern)**来解耦角色和企业这两个变化维度,让两者可以独立扩展,避免类爆炸和多重继承问题。具体实现步骤如下:
步骤1:抽象出企业行为接口
把不同企业的差异化行为抽离成独立的接口,定义员工和经理需要的企业专属方法:
// 企业员工行为接口 class IEmployeeCompanyBehavior { public: virtual void StartOnboarding() = 0; virtual void StartOffboarding() = 0; virtual void StartAppraisal() = 0; virtual ~IEmployeeCompanyBehavior() = default; }; // 企业经理行为接口 class IManagerCompanyBehavior { public: virtual void StartTeamAppraisal() = 0; virtual ~IManagerCompanyBehavior() = default; };
步骤2:实现各企业的行为类
为每个企业实现对应的行为类,封装该企业的专属逻辑:
// Company1的员工行为实现 class Company1EmployeeBehavior : public IEmployeeCompanyBehavior { // Company1员工专属数据 int tasksDone; int clientsMeetingsDone; int appreciationsReceived; public: void StartOnboarding() override { // Company1专属入职流程逻辑 } void StartOffboarding() override { // Company1专属离职流程逻辑 } void StartAppraisal() override { // Company1专属绩效评估逻辑,可使用自身成员变量 } }; // Company1的经理行为实现 class Company1ManagerBehavior : public IManagerCompanyBehavior { // Company1经理专属数据 int company1specificData; public: void StartTeamAppraisal() override { // Company1专属团队评估逻辑 } }; // Company2的员工行为实现 class Company2EmployeeBehavior : public IEmployeeCompanyBehavior { int bugSolved; int featureDeveloped; public: void StartOnboarding() override { // Company2专属入职流程逻辑 } void StartOffboarding() override { // Company2专属离职流程逻辑 } void StartAppraisal() override { // Company2专属绩效评估逻辑 } }; // Company2的经理行为实现 class Company2ManagerBehavior : public IManagerCompanyBehavior { int company2specificData; public: void StartTeamAppraisal() override { // Company2专属团队评估逻辑 } };
步骤3:重构角色基类,引入行为依赖
修改Employee和Manager基类,通过组合而非继承的方式引入企业行为,把差异化行为委托给对应的行为类:
class Employee { string name, address, empId; int salary; Dept dept; // 组合企业员工行为接口 std::unique_ptr<IEmployeeCompanyBehavior> companyBehavior; public: // 构造时传入对应的企业行为实现 Employee(std::unique_ptr<IEmployeeCompanyBehavior> behavior) : companyBehavior(std::move(behavior)) {} void [Get/Set]Name(); void GetEmpid(); void SetSalary(); // 委托给行为类实现 void StartOnboarding() { companyBehavior->StartOnboarding(); } void StartOffboarding() { companyBehavior->StartOffboarding(); } void StartAppraisal() { companyBehavior->StartAppraisal(); } }; class Manager : public Employee { list teamList; int appraisalBudget; // 组合企业经理行为接口 std::unique_ptr<IManagerCompanyBehavior> managerCompanyBehavior; public: // 构造时同时传入员工和经理的企业行为实现 Manager(std::unique_ptr<IEmployeeCompanyBehavior> empBehavior, std::unique_ptr<IManagerCompanyBehavior> mgrBehavior) : Employee(std::move(empBehavior)), managerCompanyBehavior(std::move(mgrBehavior)) {} int [Get/Set]AppraisalBudget(); int [Add/Delete]EmployeeInTeam(emp); // 委托给经理行为类实现 void StartTeamAppraisal() { managerCompanyBehavior->StartTeamAppraisal(); } };
步骤4:使用方式
创建对应企业的员工和经理时,传入对应的行为实例即可:
// 创建Company1的普通员工 auto company1Emp = std::make_unique<Employee>( std::make_unique<Company1EmployeeBehavior>() ); // 创建Company1的经理 auto company1Mgr = std::make_unique<Manager>( std::make_unique<Company1EmployeeBehavior>(), std::make_unique<Company1ManagerBehavior>() ); // 创建Company2的普通员工 auto company2Emp = std::make_unique<Employee>( std::make_unique<Company2EmployeeBehavior>() );
方案优势
- 解耦维度:角色(员工/经理)和企业规则完全分离,新增企业只需实现对应的行为类,新增角色只需扩展角色基类,不会出现类爆炸。
- 避免多重继承:通过组合替代继承,彻底解决多重继承带来的菱形继承、二义性问题。
- 灵活性高:可以动态切换企业行为(比如员工转去其他公司,只需替换行为实例),符合开闭原则。
另外,也可以考虑结合模板方法模式,在角色基类中定义流程框架,把可变部分交给行为类实现,进一步细化逻辑分工,但桥接模式是解决这类多维度变化场景的核心方案。
内容的提问来源于stack exchange,提问作者user265976

