接口的实际使用
现在让我们看一下接口的实际用途。
我们将编写一个简单的程序,根据员工的个人工资计算公司的总费用。为简洁起见,我们假设所有费用均以美元为单位。
package main
import (
"fmt"
)
type SalaryCalculator interface {
CalculateSalary() int
}
type Permanent struct {
empId int
basicpay int
pf int
}
type Contract struct {
empId int
basicpay int
}
//salary of permanent employee is the sum of basic pay and pf
func (p Permanent) CalculateSalary() int {
return p.basicpay + p.pf
}
//salary of contract employee is the basic pay alone
func (c Contract) CalculateSalary() int {
return c.basicpay
}
/*
total expense is calculated by iterating through the SalaryCalculator slice and summing
the salaries of the individual employees
*/
func totalExpense(s []SalaryCalculator) {
expense := 0
for _, v := range s {
expense = expense + v.CalculateSalary()
}
fmt.Printf("Total Expense Per Month $%d", expense)
}
func main() {
pemp1 := Permanent{
empId: 1,
basicpay: 5000,
pf: 20,
}
pemp2 := Permanent{
empId: 2,
basicpay: 6000,
pf: 30,
}
cemp1 := Contract{
empId: 3,
basicpay: 3000,
}
employees := []SalaryCalculator{pemp1, pemp2, cemp1}
totalExpense(employees)
}
我们公司有两种员工,由第 11 行和第 17 行中的结构定义。长期雇员的工资是总和,而对于合同雇员来说,这只是基本工资。这在相应的方法中表示,分别在23和28行。通过声明此方法,两者和结构现在都实现了接口。
第 36 行中声明的函数表达了接口的美感。此方法将 SalaryCalculator 接口的一部分作为参数。在第 59 行中,我们将一个包含两者和类型的切片传递给函数。该函数通过调用相应类型的方法来计算费用。这是在排队的情况下完成的,在39行。
这样做的最大优点是可以扩展到任何新员工类型,而无需更改任何代码。假设公司增加了一种具有不同薪酬结构的新型员工。这可以在 slice 参数中传递,甚至不需要对函数进行任何代码更改。此方法将执行它应该执行的操作,也将实现接口:)。
让我们修改此程序并添加新员工Freelancer。Freelancer的工资是每小时工资与总工作时间的乘积。
package main
import (
"fmt"
)
type SalaryCalculator interface {
CalculateSalary() int
}
type Permanent struct {
empId int
basicpay int
pf int
}
type Contract struct {
empId int
basicpay int
}
type Freelancer struct {
empId int
ratePerHour int
totalHours int
}
//salary of permanent employee is sum of basic pay and pf
func (p Permanent) CalculateSalary() int {
return p.basicpay + p.pf
}
//salary of contract employee is the basic pay alone
func (c Contract) CalculateSalary() int {
return c.basicpay
}
//salary of freelancer
func (f Freelancer) CalculateSalary() int {
return f.ratePerHour * f.totalHours
}
/*
total expense is calculated by iterating through the SalaryCalculator slice and summing
the salaries of the individual employees
*/
func totalExpense(s []SalaryCalculator) {
expense := 0
for _, v := range s {
expense = expense + v.CalculateSalary()
}
fmt.Printf("Total Expense Per Month $%d", expense)
}
func main() {
pemp1 := Permanent{
empId: 1,
basicpay: 5000,
pf: 20,
}
pemp2 := Permanent{
empId: 2,
basicpay: 6000,
pf: 30,
}
cemp1 := Contract{
empId: 3,
basicpay: 3000,
}
freelancer1 := Freelancer{
empId: 4,
ratePerHour: 70,
totalHours: 120,
}
freelancer2 := Freelancer{
empId: 5,
ratePerHour: 100,
totalHours: 100,
}
employees := []SalaryCalculator{pemp1, pemp2, cemp1, freelancer1, freelancer2}
totalExpense(employees)
}
现在看delphi如何实现的:
program InterfaceTest2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, ArrayHelper, System.Generics.Collections;
type
int = Integer;
ISalaryCalculator = interface
['{EFFAFB71-7508-48E3-BB1E-3372B436043A}']
function CalculateSalary: Integer;
end;
TPermanent = class(TInterfacedObject, ISalaryCalculator)
private
empId ,
basicpay ,
pf :int;
public
function CalculateSalary: Integer;
constructor Create(AempId, Abasicpay , Apf: int);
end;
TContract = class(TInterfacedObject, ISalaryCalculator)
private
empId ,
basicpay: int;
public
function CalculateSalary: Integer;
constructor Create(AempId, Abasicpay: int);
end;
TFreelancer= class(TInterfacedObject, ISalaryCalculator)
private
empId,
ratePerHour,
totalHours: int;
public
function CalculateSalary: Integer;
constructor Create(AempId, AratePerHour, AtotalHours: int);
end;
//salary of permanent employee is the sum of basic pay and pf
constructor TPermanent.Create(AempId, Abasicpay , Apf: int);
begin
empId := AempId;
basicpay := Abasicpay;
pf := Apf;
end;
function TPermanent.CalculateSalary: int;
begin
Result := basicpay + pf
end;
//salary of contract employee is the basic pay alone
constructor TContract.Create(AempId, Abasicpay: int);
begin
empId := AempId;
basicpay := Abasicpay;
end;
function TContract.CalculateSalary: int;
begin
Result := basicpay
end;
//salary of freelancer
constructor TFreelancer.Create(AempId, AratePerHour, AtotalHours: int);
begin
empId := AempId;
ratePerHour := AratePerHour;
totalHours := AtotalHours
end;
function TFreelancer.CalculateSalary: int;
begin
result := ratePerHour * totalHours
end;
(*
total expense is calculated by iterating through the SalaryCalculator slice and summing
the salaries of the individual employees
*)
procedure totalExpense(s: TArray<ISalaryCalculator>);
var
expense: int;
v: ISalaryCalculator;
begin
expense := 0;
for v in s do
begin
expense := expense + v.CalculateSalary()
end;
Writeln(Format('Total Expense Per Month $%d', [expense]))
end;
procedure main();
var
pemp1, pemp2, cemp1, freelancer1, freelancer2: ISalaryCalculator;
employees: TArray<ISalaryCalculator>;
begin
pemp1 := TPermanent.Create(1, 5000, 20);
pemp2 := TPermanent.Create(2, 6000, 30);
cemp1 := TContract.Create(3, 3000);
freelancer1 := TFreelancer.Create(4, 70, 120);
freelancer2 := TFreelancer.Create(5, 100, 100);
employees := nil;
TArray.Insert<ISalaryCalculator>(employees, 0, pemp1);
TArray.Add<ISalaryCalculator>(employees, pemp2);
TArray.Add<ISalaryCalculator>(employees, cemp1);
TArray.Add<ISalaryCalculator>(employees, freelancer1);
TArray.Add<ISalaryCalculator>(employees, freelancer2);
totalExpense(employees);
SetLength(employees, 0);
end;
begin
try
main{ TODO -oUser -cConsole Main : Insert code here }
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
不得不承认,delphi的代码要冗长很多,而且用到一个开源的单元文件:ArrayHelper,才有Add方法可用。
输出是一样的
Total Expense Per Month $14050