如何为各种相似实体使用固定的类层次结构,例如公司 1,2,3 的 employee-Manager

How to make use of a fixed hierarchy of classes for various similar entities, like employee-Manager for company 1,2,3

提问人:user265976 提问时间:6/29/2023 最后编辑:halferuser265976 更新时间:7/7/2023 访问量:68

问:

我有一个类说 Employee 和一个子类(Employee 的)说 Manager

Employee 类中有各种方法(和数据成员),与工资单、员工详细信息、评估等相关。同样,对于管理器,有多种方法。

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 等,将来可以添加更多。员工或经理可以是公司 1、公司 2 等。

公司 1 的员工和经理的关系与上述类似,公司 2 的关系相同。但是他们将有不同的方法来处理可用的方法。就像 company1 的员工的 startOnboarding() 与 company2 的员工不同,同样,company1 经理的 startTeamAppraisal() 将与公司 2 的经理不同。

现在,对此方案进行建模的一种方法是为每个公司(如 EmployeeCompany1、EmployeeCompany2)创建不同的 Employee 子类,并为每家公司(如 ManagerCompany1、ManagerCompany2 等)创建类似的 Manager 子类

不同公司的员工等级:

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()  { ... }
};

但在上述情况下,EmployeeCompany[1,2,..] 将是 Employee 的子类,而 Manager 已经是 Employee 的子类,但它们(EmployeeCompany[1,2..] 和 Manager)与所考虑的行为不在同一级别。所以设计上存在一些缺陷。

如果我们对 ManagerCompany1 执行类似操作,那么它必须是 EmployeeCompany1 的子类,但它也必须是 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
    }
};

问题:

  1. 我觉得我的设计有缺陷,我描述的场景在面向对象设计文献中是一个定义明确的场景。

  2. 我正在寻找社区的帮助,以更好地设计方法来在 c++ 中对上述场景进行建模。

C++ OOP 设计 模式 虚拟继承

评论

0赞 Drew Dormann 6/29/2023
您能澄清一下您关注的编程问题是什么吗?我不认为有人问过问题。
0赞 user265976 6/29/2023
我正在寻求帮助,以便为我在问题中描述的场景提出更好的类设计。
3赞 Alan Birtles 6/29/2023
如果是公司不同,则将该方法放在 company 类上,并将 employee 作为参数传入StartOnboarding()
1赞 user265976 6/29/2023
@DrewDormann 感谢您的指出,我已经编辑了专门询问我寻求帮助的内容。
0赞 Pepijn Kramer 6/29/2023
1. 将所有虚拟方法移动到抽象基类,比如 EmployeeItf'', 2.从中派生 Employee(和 Manager)。若要存储多个实例,请使用 std::vector<std::unique_ptr<EmployeeItf>>

答:

0赞 Amit 6/29/2023 #1

我认为模板是解决这个问题的好方法。试着弄清楚不同公司之间的确切区别,并生成一个通用的界面。

class Company {
public:
  struct StartOnboardingParams { ... };
  virtual static StartOnboardingParams getSOBParams(...);
};

class Company1 : public Company { ... };

template <typename CompanyType>
class Employee {
static_assert(std::is_base_of<Company, CompanyType>::value, "CompanyType must be derived from Company");
public:
   virtual void StartOnboarding() { /* here you can use Company::getSOBParams */ }
}

template <typename Company>
class Manager : public Employee<Company> { ... };

在这种情况下,of 仅继承自 of,而不是从任何其他公司的员工那里继承,这解决了设计中的缺陷。ManagerCompany1EmployeeCompany1

模板化主题的确切假设和内容可能不平凡,需要对界面进行一些更改,但总的来说,这种方法应该会有所帮助。

0赞 Peter 6/29/2023 #2

从设计的角度来看,你的想法在我看来是倒退的。

员工就是一个人。公司(或部门)不是个人的一部分 - 它是一个独特的(逻辑)实体,管理员工集合、分配/撤销管理权限、支付工资以及启动入职和离职流程。出于自己的目的,该公司还将员工 ID 之类的东西与每个员工相关联——它(通常)不会在每个员工的额头上纹上 ID,因此 ID 不是员工的财产。

此外,一个人可能有不止一份工作——例如,为多家公司兼职工作。但是,该人与公司1的关系(具体)不会影响该人与公司2的关系。一个人可能是公司 1 的经理,但(例如,如果公司 1 破产且不支付工资),并且也是公司 2 的看门人。

经理和其他员工之间唯一真正的区别是他们有不同的角色。该部门有许多角色,并将一个或多个角色与每位员工相关联。

考虑到这一点,我会做类似的事情

 class Employee
 {
      // attributes, setters, getters for name, address
 };

 class Department
 {
     public:
     void OnBoard(Employee &);    // set up pay, employee ID, etc
     void Offboard(Employee &);
     
     void PayAllEmployees();  //  pay every employee

     RoleDescription CreateRole(RoleAttributes);   // different roles for staff, cleaners, managers

     void AssignRole(EmployeeID, RoleDescription);
     void UnassignRole(EmployeeID, RoleDescription);

 };

然后将公司构建为部门的集合。

如果不同的部门或公司有不同的程序(例如,入职、入职、离职等),则将相关功能虚拟化,并在派生类中覆盖它们。它不是每个部门一个班级(或每个公司一个班级)。每个部门(或公司)类别一个类别。例如,会计部门可能与与工厂运营有关的部门具有不同的程序。审计公司可能拥有与汽车制造商不同的部门。

作为虚拟职能的替代方法,您还可以使用模板(例如,公司可能由一系列部门组成,每个部门可能具有一组不同的属性)。