用一张组织架构图说清楚类和对象
@
背景
在刚跨入面向对象开发的初始阶段,对于类和对象的理解往往是程序员碰到的第一个难题,本文旨在用一个具体的例子转化为JAVA代码,把OOP中类和对象的基础概念通过程序的方式表述清楚。
组织结构图
在《程序员这生必须掌握的两种图形》这篇文章中,我们提到了组织结构图,比如下面这张图:图中按层次分成了四个部门(把总经理室看作最高部门),每个部门有一个主管;每个部门各分为两个组,每个组人员若干。
抽象
从面向对象开发的基础概念中类是一个抽象,那接下来,我们尽量发挥一下自己大脑的抽象理解能力,把上面的组织架构图做一次完整的抽象,便于我们能把类能抽取出来:
第一次抽象过程
我们把组织架构从组成上做个划分:可以分成公司、部门、组、组员,且这些组成有大小包含 关系。
第二次抽象过程
我们再把普遍相似的做一次归类:把原来的部门看作是大部门,把组看作是小部门;看总经理、主管、组长、组员都归类为职员。
定义类
静态数据
经过上面两次抽象过程,我们把组织架构中共性的实体分类了以下三类:
- 公司:代表了组织架构的外在存在;公司是由部门和职员组成的一个完整实体。
- 部门:代表了组织架构中的运作单位;部门按类型不同可以分为不同的业务部门。
- 职员:代表了组织架构中的最小单位;职员按职位不同存在于不同的业务部门。
有了以上抽象类的不同描述,我们可以通过具体的代码来描述这些类。
/**
* 用组织架构图理解类和对象--公司类
* * @author zhuhuix
* @date 2020-05-22
*/
public class Company {
//公司id
private int id;
//公司名称
private String name;
//公司部门列表
private List<Department> departments;
}
/**
* 用组织架构图理解类和对象--部门类
*
* @author zhuhuix
* @date 2020-05-22
*/
public class Department {
//部门id
private int id;
//部门名称
private String name;
//上级部门
private Integer parentId;
//部门职员列表
private List<Employee> employees;
}
/**
* 用组织架构图理解类和对象--职员类
*
* @author zhuhuix
* @date 2020-05-22
*/
public class Employee {
//职员id
private int id;
//职员姓名
private String name;
//职员性别
private String sex;
//职员年龄
private int age;
//职员职位
private String position;
//入职日期
private Date hireDate;
//当前薪水
private BigDecimal salary;
}
动态行为
上面我们把类从静态数据层面做了定义,也就是说类有了自己的属性:比如员工类有姓名,年龄等属性,部门类有部门名称,上级部门等属性,公司类有部门列表等属性。
但光有这些静态属性是不够的,我们还要让组织架构图动起来,也就是说让这些类增加成员方法。
- 公司会有增加部门、裁撤部门的行为
- 部门会有增加职员、裁撤职员的行为
- 职员会有升职、调岗、调动的行为。
我们把这些涉及组织架构动态变化的行为作为成员方法加入到对应的类中:
/**
* 用组织架构图理解类和对象--公司类
*
* @author zhuhuix
* @date 2020-05-22
*/
public class Company {
...
//增加部门
public void addDepartment(Department department){
this.departments.add(department);
}
//裁撤部门
public void deleteDepartment(Department department){
this.departments.remove(department);
}
//定位部门
Department findDepartmentByName(String departmentName) {
Optional<Department> optional = departments.stream().filter(department ->
department.getName().equals(departmentName)).findFirst();
return optional.get();
}
}
/**
* 用组织架构图理解类和对象--部门类
* * @author zhuhuix
* @date 2020-05-22
*/
public class Department {
...
//增加职员
public void addEmployee(Employee employee){
this.employees.add(employee);
}
//裁撤职员
public void deleteEmployee(Employee employee){
this.employees.remove(employee);
}
}
/**
* 用组织架构图理解类和对象--职员类
* * @author zhuhuix
* @date 2020-05-22
*/
public class Employee {
...
//升职、调岗、调动
public void setPosition(String position){
this.position = position;
}
}
类的完整结构
创建对象
在上面的所有表述中,我们做得是对组织架构图的抽象,也就是完成类的定义。
接下来我们从抽象概念回到现实世界中
- 公司抽象类的具体实现对象是互联网股份有限公司
- 部门抽象类的具体实现对象是总经理室、研发部、市场部、产品部、产品部下面的产品A组/B组..
- 职员抽象类的具体实现对象是总经理Mike,研发部主管Jack、产品A组Jerry…
也就是组织结构图上实实在在存在的单位、部门及人员,当然这些对象必须是通过类进行创建的,下面来完成创建组织架构的实例代码:
对象的初始化
这里必须要引入类的构造函数的概念,有人不太理解构造函数到底有什么用,你可以简单的把它认为就是完成对象的初始化,比如公司建立时要设定公司名称,部门设立时要设定部门名称,部门职责,人员加入公司时要充定岗位薪资等。我们先给上面的几个类加个对应的构造函数。
public class Company {
//公司id
private int id;
//公司名称
private String name;
//公司部门列表
private List<Department> departments;
//初始化构造函数
Company(int id,String name){
this.id=id;
this.name=name;
this.departments = new ArrayList<>();
}
}
public class Department {
//部门id
private int id;
//部门名称
private String name;
//上级部门
private Integer parentId;
//部门职员列表
private List<Employee> employees;
//初始化构造函数
Department(int id,String name,Integer parentId){
this.id=id;
this.name=name;
this.parentId=parentId;
this.employees = new ArrayList<>();
}
}
...
}
public class Employee {
//职员id
private int id;
//职员姓名
private String name;
//职员性别
private String sex;
//职员年龄
private int age;
//职员职位
private String position;
//入职日期
private Date hireDate;
//当前薪水
private BigDecimal salary;
//初始化构造函数
public Employee(int id, String name, String sex, int age, String position, Date hireDate, BigDecimal salary) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
this.position = position;
this.hireDate = hireDate;
this.salary = salary;
}
}
组织架构的建立
有了类及构造函数完成对象的初始化过程,我们就具备了建立整个组织架构的能力,接下来我们完整地建立一个公司的组织架构:
/**
* 用组织架构图理解类和对象
*
* @author zhuhuix
* @date 2020-05-22
*/
public class OrganizationBuild {
//定义一个全局静态变量,作为控制组织架构的id
public static int id = 0;
;
public static void main(String[] args) {
//设立公司
Company company = new Company(id++, "互联网股份有限公司");
//公司设立总经理室
Department manageDept = new Department(id++, "总经理室", null);
company.addDepartment(manageDept);
//在总经理室下设立产品部
Department productDept = new Department(id++, "产品部", manageDept.getId());
company.addDepartment(productDept);
//在产品部下设立产品A、B组
company.addDepartment(new Department(id++, "产品A组", productDept.getId()));
company.addDepartment(new Department(id++, "产品B组", productDept.getId()));
//在总经理室下设立研发部
Department developmentDept = new Department(id++, "研发部", manageDept.getId());
company.addDepartment(developmentDept);
//在研发部下设立软件组与硬件组
company.addDepartment(new Department(id++, "软件组", developmentDept.getId()));
company.addDepartment(new Department(id++, "硬件组", developmentDept.getId()));
//在总经理室下设立市场部
Department marketDept = new Department(id++, "市场部", manageDept.getId());
company.addDepartment(marketDept);
//在市场部下设立创意组与渠道组
company.addDepartment(new Department(id++, "创意组", marketDept.getId()));
company.addDepartment(new Department(id++, "渠道组", marketDept.getId()));
//总经理室人事任命
manageDept.addEmployee(new Employee(id++, "Mike", "男", 35, "总经理",
new Date(), BigDecimal.valueOf(100000)));
manageDept.addEmployee(new Employee(id++, "Tom", "男", 34, "副总经理",
new Date(), BigDecimal.valueOf(60000)));
//研发部人事任命
developmentDept.addEmployee(new Employee(id++, "Jack", "男", 30, "研发部主管",
new Date(), BigDecimal.valueOf(40000)));
company.findDepartmentByName("软件组")
.addEmployee(new Employee(id++, "Kate", "女", 26, "组员",
new Date(), BigDecimal.valueOf(20000)));
company.findDepartmentByName("硬件组")
.addEmployee(new Employee(id++, "Will", "男", 24, "组员",
new Date(), BigDecimal.valueOf(20000)));
//产品部人事任命
productDept.addEmployee(new Employee(id++, "Jerry", "男", 28, "产品部主管",
new Date(), BigDecimal.valueOf(40000)));
company.findDepartmentByName("产品A组")
.addEmployee(new Employee(id++, "Merry", "女", 28, "组员",
new Date(), BigDecimal.valueOf(20000)));
company.findDepartmentByName("产品B组")
.addEmployee(new Employee(id++, "Leo", "男", 27, "组员",
new Date(), BigDecimal.valueOf(20000)));
//市场部人事任命
marketDept.addEmployee(new Employee(id++, "Rose", "女", 29, "市场部主管",
new Date(), BigDecimal.valueOf(40000)));
company.findDepartmentByName("创意组")
.addEmployee(new Employee(id++, "Amy", "", 25, "组员",
new Date(), BigDecimal.valueOf(20000)));
company.findDepartmentByName("渠道组")
.addEmployee(new Employee(id++, "Tony", "男", 23, "组员",
new Date(), BigDecimal.valueOf(20000)));
//遍历公司组织结构
int deptCount = 0;
int empCount = 0;
Iterator<Department> deptIterator = company.getDepartments().iterator();
while (deptIterator.hasNext()) {
deptCount++;
Department department = deptIterator.next();
System.out.println("部门:" + department.getName());
if (department.getEmployees() != null) {
Iterator<Employee> empIterator = department.getEmployees().iterator();
while (empIterator.hasNext()) {
empCount++;
Employee employee = empIterator.next();
System.out.print(" 人员:" + employee.getName() + " 职位:" + employee.getPosition() + ",");
}
System.out.println();
}
}
System.out.println("总共部门数:" + deptCount);
System.out.println("总共职员数:" + empCount);
}
}
输出结果如下:
结语
面向对象编程,我们主要锻炼一种能力和掌握一个技巧:
一种能力就是抽象理解能力:将具体的对象通过归类识别,进行抽象理解,找到共性的静态数据和动态行为,形成完整的类定义。
一个技巧就是先静态后动态,先提炼抽象事物的属性名词,再根据这些属性名词具体有哪些行为,形成成员方法。