@
背景
在剛跨入面向對象開發的初始階段,對於類和對象的理解往往是程序員碰到的第一個難題,本文旨在用一個具體的例子轉化為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);
}
}
輸出結果如下:
結語
面向對象編程,我們主要鍛煉一種能力和掌握一個技巧:
一種能力就是抽象理解能力:將具體的對象通過歸類識別,進行抽象理解,找到共性的靜態數據和動態行為,形成完整的類定義。
一個技巧就是先靜態后動態,先提煉抽象事物的屬性名詞,再根據這些屬性名詞具體有哪些行為,形成成員方法。