背景
- 处理有异同项的类是难点
- 同项可继承或拥有,如下文学生类和工人类
- 趁早合并向上传参,可减少代码的复杂度
汇总
- 抽象:差异类,共享构造+独立方法
- 泛型:差异类,共享构造+方法,对抽象改进
- 继承:合并类,无泛型传参,对泛型改进
- 接口:合并接口
- 拥有:合并类,非继承公有类,语义更清晰
继承人员
using System.Diagnostics;
namespace NotLiskov
{
// 抽象基类
abstract class Person
{
public string Name { get; }
public char Sex { get; }
protected Person(string name, char sex)
{
Debug.Assert(!string.IsNullOrEmpty(name));
Debug.Assert(sex == 'F' || sex == 'M');
Name = name;
Sex = sex;
}
}
// 学生子类
class Student : Person
{
public string Subject { get; } // 独有项
public Student(string name, char sex, string subject)
: base(name, sex)
{
Debug.Assert(!string.IsNullOrEmpty(subject));
Subject = subject;
}
}
// 工人子类
class Worker : Person
{
public int Salary { get; } // 独有项
public Worker(string name, char sex, int salary)
: base(name, sex)
{
Debug.Assert(salary > 0);
Salary = salary;
}
}
}
拥有人员
using System.Diagnostics;
namespace NotLiskov
{
// 非基类
class Solo
{
public string Name { get; }
public char Sex { get; }
public Solo(string name, char sex)
{
Name = name;
Sex = sex;
}
}
class SoloStudent
{
public Solo Person { get; } // 共有项,拥有而非继承
public string Course { get; }
public SoloStudent(Solo p, string course)
{
Debug.Assert(p != null);
Debug.Assert(!string.IsNullOrEmpty(course));
Person = p;
Course = course;
}
}
class SoloWorker
{
public Solo Person { get; } // 共有项,拥有而非继承
public int Salary { get; }
public SoloWorker(Solo p, int salary)
{
Debug.Assert(p != null);
Debug.Assert(salary > 0);
Person = p;
Salary = salary;
}
}
}
抽象
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace NotLiskov
{
// - 类内泛型T,类内有效,不能采用ctor<T>
// - T不同时,类不同
// - 向上传参时,仍需明确T,不利传参
abstract class AbstractCalculator<T>
{
protected readonly List<T> _people;
// 共享构造
public AbstractCalculator(List<T> people)
{
Debug.Assert(people.Count > 0);
_people = people;
}
public abstract int Count(char sex);
}
class WorkerAbstractCalculator : AbstractCalculator<Worker>
{
public WorkerAbstractCalculator(List<Worker> workers) : base(workers) { }
public override int Count(char sex)
=> _people.Count(x => x.Sex == sex);
}
class StudentAbstractCalculator : AbstractCalculator<Student>
{
public StudentAbstractCalculator(List<Student> students) : base(students) { }
public override int Count(char sex)
=> _people.Count(x => x.Sex == sex);
}
}
泛型
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace NotLiskov
{
// - T: someClass,限定类或其子类
class GernericCalculator<T> : ICalculator where T : Person
{
readonly List<T> _people;
// 共享构造
public GernericCalculator(List<T> people)
{
Debug.Assert(people.Count > 0);
_people = people;
}
// 共享方法
public int Count(char sex)
=> _people.Count(x => x.Sex == sex);
}
}
继承
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace NotLiskov
{
class Calculator
{
// List<T>支持不变,输入类型必须完全相等
// IEnumerable<T>支持协变
readonly IEnumerable<Person> _people;
public Calculator(IEnumerable<Person> people)
{
Debug.Assert(people.Count() > 0);
_people = people;
}
public int Count(char sex)
=> _people.Count(x => x.Sex == sex); // 提升为基类后,调用共用属性
}
}
接口
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace NotLiskov
{
interface ICalculator
{
int Count(char sex);
}
// 继承接口,但需分别处理构造方法
// - 实现异类合并
// - 向上传参时,无需构造函数
class WorkerCalculator : ICalculator
{
readonly List<Worker> _workers;
public WorkerCalculator(List<Worker> workers)
{
Debug.Assert(workers.Count > 0);
_workers = workers;
}
public int Count(char sex)
=> _workers.Count(x => x.Sex == sex);
}
class StudentCalcutor : ICalculator
{
readonly List<Student> _students;
public StudentCalcutor(List<Student> students)
{
Debug.Assert(students.Count > 0);
_students = students;
}
public int Count(char sex)
=> _students.Count(x => x.Sex == sex);
}
}
拥有
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace NotLiskov
{
class SoloCalculator
{
readonly List<Solo> _people;
public SoloCalculator(List<Solo> people)
{
Debug.Assert(people.Count() > 0);
_people = people;
}
public int Count(char sex)
=> _people.Count(x => x.Sex == sex); // 提升为基类后,调用共用属性
}
}
客户代码
using System.Collections.Generic;
using System.Linq;
using static System.Console;
namespace NotLiskov
{
class Program
{
static void Main(string[] args)
{
var workers = new List<Worker>
{
new Worker("张三", 'M', 8000),
new Worker("李四", 'M', 7000),
};
var students = new List<Student>
{
new Student("王五", 'M', "Chinese"),
new Student("小六", 'F', "Math"),
};
var soloWorkers = new List<SoloWorker>
{
new SoloWorker(new Solo("张三", 'M'), 8000),
new SoloWorker(new Solo("李四", 'M'), 7000),
};
var soloStudents = new List<SoloStudent>
{
new SoloStudent(new Solo("王五", 'M'), "Chinese"),
new SoloStudent(new Solo("小六", 'F'), "Math"),
};
// [1#]抽象,实例异类
WriteLine("\n----抽象");
AbstractCalculator<Worker> a1 = new WorkerAbstractCalculator(workers);
WriteLine($"工人数(男): {a1.Count('M')}");
AbstractCalculator<Student> a2 = new StudentAbstractCalculator(students);
WriteLine($"学生数(男): {a2.Count('M')}");
// [2#]泛型,实例异类
WriteLine("\n----泛型");
var g1 = new GernericCalculator<Worker>(workers);
WriteLine($"工人数(男): {g1.Count('M')}");
var g2 = new GernericCalculator<Student>(students);
WriteLine($"学生数(男): {g2.Count('M')}");
// [3#]继承,实例同类
WriteLine("\n----继承");
var c = new Calculator(workers);
WriteLine($"工人数(男): {c.Count('M')}");
c = new Calculator(students);
WriteLine($"学生数(男): {c.Count('M')}");
// [4#]接口,实例同接口
WriteLine("\n----接口");
ICalculator i = new WorkerCalculator(workers);
WriteLine($"工人数(男): {i.Count('M')}");
i = new StudentCalcutor(students);
WriteLine($"学生数(男): {i.Count('M')}");
// [5#]拥有,实例同类
WriteLine("\n----拥有");
var s = new SoloCalculator(
soloWorkers.Select(x => x.Person).ToList());
WriteLine($"工人数(男): {s.Count('M')}");
s = new SoloCalculator(
soloStudents.Select(x => x.Person).ToList());
WriteLine($"学生数(男): {s.Count('M')}");
}
}
}
网友评论