我对接口/抽象类/类有相当的了解,但只是想了解其他内容。请看下面的代码:
namespace AbstractClassExample
{
class Program
{
static void Main(string[] args)
{
BaseEmployee fullTimeEmployee = new FullTimeEmployee();
BaseEmployee contractEmployee = new ContractEmployee();
}
}
public abstract class BaseEmployee
{
public string EmployeeID { get; set; }
public string EmployeeName { get; set; }
public string EmployeeAddress { get; set; }
public abstract double CalculateSalary(int hoursWorked);
}
public class FullTimeEmployee : BaseEmployee
{
public override double CalculateSalary(int hoursWorked)
{
//do something
}
}
public class ContractEmployee : BaseEmployee
{
public override double CalculateSalary(int hoursWorked)
{
//do something
}
}
}
然而,我没有达到线下(第一种方法):
BaseEmployee fullTimeEmployee = new FullTimeEmployee();
BaseEmployee contractEmployee = new ContractEmployee();
为什么不这样写(第二种方法):
FullTimeEmployee fullTimeEmployee = new FullTimeEmployee();
完全可以使用第二种方法,它将起作用关系。如果上面的抽象类在DLL中,那么工作中的任何开发人员将如何知道。当您与您或某种文档进行编码时,可能会使用第一种方法。不是吗?
类似的例子也适用于接口声明。像:
interface IPointy {
void MyMethod();
}
class Pencil : IPointy {
void MyMethod() {
}
void MyOtherMethod() {
}
}
IPointy itPt = new Pencil();
不是第一种让它变得复杂的方法吗?什么是好的做法?任何良好的练习与第一和第二的不良练习第二?
答案 0 :(得分:0)
使用第一种方法启用多态性。
假设你有一个公司类:
class Company {
}
当然,公司有全职和合同雇员。我们将它们添加为属性:
public FullTimeEmployee[] EmployeesFullTime { get; set; }
public ContractEmployees[] EmployeesContract { get; set; }
这似乎都很好。
但是,如果您的公司现在可以拥有另一种有不同方式计算薪水的员工呢?您必须添加另一个属性:
public FullTimeEmployee[] EmployeesFullTime { get; set; }
public ContractEmployee[] EmployeesContract { get; set; }
public AnotherKindOfEmployee[] EmployeesOther { get; set; }
这不好,是吗?每次添加新员工时,都必须添加其他属性!
这就是你使用BaseEmployee
的原因,它不关心它拥有什么样的员工,它仍然可以计算薪水!
public BaseEmployee[] AllEmployees { get; set; }
答案 1 :(得分:0)
您将FullTimeEmployee
分配给BaseEmployee
的原因之一是您可以将它们放在FullTimeEmployees' and
ContractEmployees`的集合中:
List<BaseEmployee> allEmployees = new List<BaseEmployee>()
{
new FullTimeEmployee() {...},
new FullTimeEmployee() {...},
new ContractEmployee() {...},
new FullTimeEmployee() {...},
}
这样做的缺点是,您无法使用({1}} FullTimeEmployee
ContractEmployees
没有的allEmployees
功能,但如果您在处理{{1}时不需要此功能这个方法比创建两个员工集合更可取。例如,您可以编写一个适用于FullTimeEmployees
和ContractEmployees
的函数:
private void PaySalary(List<BaseEmployee> employees)
{
foreach (var employee in employees)
{
var salary = employee.CalculateSalary()
Pay(salary, ...);
}
}
创建面向对象设计时的一个指导原则是您应该设计变更,这意味着您的设计应该可以轻松地为您的设计添加类型,或者更改类的内部。
假设您需要一种新型员工HiredEmployees
。因为你是从BaseEmployee
派生的,所以你知道你可以计算他们的工资。您不必更改函数PaySalary
。
如果你给了FullTimeEmployee
和你的ContractEmployee
接口,这也会有用:
interface ISalaryReceiver
{
double CalculateSalary(int hoursWorked);
}
class BaseEmployee
{
public string EmployeeID { get; set; }
...
}
class FullTimeEmployee : BaseEmployee, ISalaryReceiver
{
public override double CalculateSalary(int hoursWorked)
{
...
}
}
class ContractEmployee : BaseEmployee, ISalaryReceiver
{
public double CalculateSalary(int hoursWorked)
{
...
}
}
void PaySalary(List<ISalaryReceiver> employees)
{
...
}
此方法可行。它甚至可以做出改变:只要它实现了ISalaryReceiver
,你就可以发明任何员工。
假设您的BaseEmploye具有需要CalculateSalary的函数:
class BaseEmployee
{
...
public void PaySalary()
{
double salary = ... // how to calculate the salary?
}
}
您不能让BaseEmployee
实施ISalaryReceiver
,因为BaseEmployee
不知道如何计算工资。
使用抽象方法时,您可以告诉BaseEmployee
,BaseEmployee
的每个对象都知道如何CalculateSalary
:
abstract class BaseEmployee
{
abstract double CalculateSalary(...);
public void PaySalary()
{
double salary = this.CalculateSalary(...);
...
}
}
因此,如果您的基类需要每个派生类不同的函数,并且没有正确的默认功能,那么您的基类需要一个抽象函数。保证每个派生类都实现了这个函数,因此基类可以调用它。
因为在这种情况下创建基类的对象没有意义(毕竟,基类不知道如何CalculateSalary
),所以基类必须被声明为abstract,结果是你不能创建基类的对象。只能创建实现CalculateSalary
的派生类的对象。
答案 2 :(得分:0)
抽象类的一个好处是 - 您可以在方法中使用抽象类型作为参数类型。
假设您有一个public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
类,方法<div class="container">
<div class="row">
<div class="col-xs-12 col-md-6 col-lg-6">A</div>
<div class="col-xs-12 col-md-6 col-lg-6">B</div>
<div class="col-xs-12 col-md-12 col-lg-6">C</div>
<div class="col-xs-12 col-md-12 col-lg-6">D</div>
</div>
</div>
在生成报告时需要计算员工薪水
Report
您不希望在需要计算工资的每种方法中使用Generate
语句
因此,public class Report
{
public SalaryReport Generate(BaseEmployee employee)
{
// ...
var salary = employee.CalculateSalary();
// ...
}
}
类并不关心if..else
如何实现,它只关心Report
类有这种方法。