回顧
先回顧下面向?qū)ο蟮娜齻€基本特性:
- 封裝
- 繼承
- 多態(tài)
Java作為面向?qū)ο蟮耐跽撸韵率纠昝赖恼宫F(xiàn)了面向?qū)ο蟮娜齻€基本特征。
public class Main {
public static void main(String[] args) {
List<Payroll> all = new ArrayList<>();
//員工類封裝了數(shù)據(jù)(姓名鸭津、年齡盒卸、性別)和行為(計算薪酬)
//銷售員工和技術(shù)員工繼承自員工類较雕,都實(shí)現(xiàn)了計算薪酬的接口
//機(jī)器不是員工搪缨,但實(shí)現(xiàn)了計算薪酬的接口食拜,也可以計算薪酬
all.add(new SaleEmployee());
all.add(new TechEmployee());
all.add(new Machine());
//多態(tài):不管是人還是機(jī)器,只要實(shí)現(xiàn)了Payroll接口副编,就都可以正確的計算出各自的薪酬
for (Payroll payroll : all) {
System.out.println(payroll.calcSalary());
}
}
}
那么Go語言呢负甸?我們一起來探索下Go語言的面向?qū)ο螅葟念惖姆庋b開始痹届。
封裝
員工薪酬示例中呻待,Java里的Employee類是這樣的:
public abstract class Employee implements Payroll {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
這里暫時先關(guān)注員工類的三個屬性,Go里面它確實(shí)沒有類队腐,要表示上面的員工對象蚕捉,它是用struct的(和C很像):
type Employee struct {
Name string
Sex string
Age int
}
看起來簡潔多了,注意到Go里面沒有private public的修飾符柴淘,它是用屬性的首個字母大小寫來區(qū)分private public迫淹,小寫字母開頭的是私有屬性,大寫字母開頭表示公開屬性为严。對象的實(shí)例化和使用對比:
//由于Employee是抽象類敛熬,不能實(shí)例化,直接用子類TechEmployee實(shí)例化
Employee tech = new TechEmployee();
tech.setName("lee");
System.out.println(tech.getName());
//這里的object.是包名第股,Employee放在object目錄下
tech := object.Employee{
Name: "lee",
Sex: "male",
Age: 20,
}
tech.Name = "bruce lee"
fmt.Println(tech.Name)
另外应民,struct中是沒有方法(行為)的,少了這個不是等于封裝特征缺了只腳嗎夕吻?當(dāng)然不是了瑞妇,Go語言里對應(yīng)面向?qū)ο罄锏某蓡T方法不是定義在struct里面,而是直接定義在struct外面梭冠,和struct平級,這里定義一個類似Java中的toString方法:
type Employee struct {
Name string
Sex string
Age int
}
func (e *Employee) ToString() string {
return "name=" + e.Name + ";sex=" + e.Sex + ";age=" + strconv.Itoa(e.Age)
}
這里(e *Employee)叫做方法的接收者改备,有點(diǎn)怪異控漠,我們可以這樣理解:
- Go里沒有this,要自己加個類似this的東西悬钳,用于指代方法對應(yīng)的實(shí)例盐捷,括號里前面的e相當(dāng)于this,當(dāng)然名字可以隨便取默勾。
- 方法定義和struct平級碉渡,如果不加個接收者定義,哪里知道這個方法屬于誰的呢母剥,括號里后面的類型表示這個方法屬性于誰的滞诺,這里可以用(e Employee)或(e *Employee)形导,區(qū)別是傳值還是傳指針,一般統(tǒng)一用后者习霹。
繼承
接下來繼承朵耕,先看看Java的:
public class TechEmployee extends Employee {
private double salaryPerMonth;
public double getSalaryPerMonth() {
return salaryPerMonth;
}
public void setSalaryPerMonth(double salaryPerMonth) {
this.salaryPerMonth = salaryPerMonth;
}
@Override
public double calcSalary() {
return salaryPerMonth;
}
}
public class SaleEmployee extends Employee {
private Double baseSalary;
private Double extraRate;
public Double getBaseSalary() {
return baseSalary;
}
public void setBaseSalary(Double baseSalary) {
this.baseSalary = baseSalary;
}
public Double getExtraRate() {
return extraRate;
}
public void setExtraRate(Double extraRate) {
this.extraRate = extraRate;
}
@Override
public double calcSalary() {
return baseSalary * (1 + extraRate);
}
}
同樣,Go里面也沒有像Java中類似extend繼承的語法淋叶,Go是用了類似Java里組合的東西來讓語法看起來像繼承:
type TechEmployee struct {
Employee
SalaryPerMonth float32
}
type SaleEmployee struct {
Employee
BaseSalary float32
ExtraRate float32
}
對應(yīng)的實(shí)例化和使用:
//實(shí)例化時阎曹,是傳了個employee
tech := object.TechEmployee{
Employee: object.Employee{Name: "lee"},
SalaryPerMonth: 10000,
}
//這里看起來像擁有了Employee的name屬性,可以設(shè)置和訪問
tech.Name = "bruce lee"
fmt.Println(tech.Name)
多態(tài)
關(guān)于多態(tài)煞檩,必須要提接口处嫌,終于Go里也是有接口的了:
public interface Payroll {
double calcSalary();
}
type Payroll interface {
CalcSalary() float32
}
接口的實(shí)現(xiàn):
public class Machine implements Payroll {
@Override
public double calcSalary() {
return 0;
}
}
type TechEmployee struct {
Employee
SalaryPerMonth float32
}
func (e *TechEmployee) CalcSalary() float32 {
return e.SalaryPerMonth
}
type Machine struct {
}
func (e *Machine) CalcSalary() float32 {
return 0
}
可以看出,Java里比較直觀斟湃,語法里直接寫著實(shí)現(xiàn)xxx接口熏迹,Go相比的話,沒那么直觀桐早,但更靈活癣缅,它沒有指定實(shí)現(xiàn)哪個接口,而是如果定義了一個相同名字和返回值的方法哄酝,就認(rèn)為是實(shí)現(xiàn)了對應(yīng)擁有這個方法的接口友存,這里假如接口有兩個方法,對應(yīng)也必須要兩個方法都有定義了陶衅,才認(rèn)為是實(shí)現(xiàn)了接口屡立。
最后,看一下集成使用的對比:
List<Payroll> all = new ArrayList<>();
//員工類封裝了數(shù)據(jù)(姓名搀军、年齡膨俐、性別)和行為(計算薪酬)
//銷售員工和技術(shù)員工繼承自員工類,都實(shí)現(xiàn)了計算薪酬的接口
//機(jī)器不是員工罩句,但實(shí)現(xiàn)了計算薪酬的接口焚刺,也可以計算薪酬
all.add(new SaleEmployee());
all.add(new TechEmployee());
all.add(new Machine());
//多態(tài):不管是人還是機(jī)器,只要實(shí)現(xiàn)了Payroll接口门烂,就都可以正確的計算出各自的薪酬
for (Payroll payroll : all) {
System.out.println(payroll.calcSalary());
}
var all [3] object.Payroll
all[0] = &object.TechEmployee{
Employee: object.Employee{Name: "lee"},
SalaryPerMonth: 10000,
}
all[1] = &object.SaleEmployee{
Employee: object.Employee{Name: "lee"},
BaseSalary: 10000,
ExtraRate: 0.1,
}
all[2] = &object.Machine{}
for _, item := range all {
fmt.Println(item.CalcSalary())
}