美文网首页
{C#} 非里氏替换的合并

{C#} 非里氏替换的合并

作者: 码农猫爸 | 来源:发表于2023-08-12 15:30 被阅读0次

    背景

    • 处理有异同项的类是难点
    • 同项可继承或拥有,如下文学生类和工人类
    • 趁早合并向上传参,可减少代码的复杂度

    汇总

    • 抽象:差异类,共享构造+独立方法
    • 泛型:差异类,共享构造+方法,对抽象改进
    • 继承:合并类,无泛型传参,对泛型改进
    • 接口:合并接口
    • 拥有:合并类,非继承公有类,语义更清晰

    继承人员

    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')}");
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:{C#} 非里氏替换的合并

          本文链接:https://www.haomeiwen.com/subject/cvmxmdtx.html