六大设计原则【单一职责】【里氏替换】【 迪米特法则】
设计模式:面向对象语言开发过程中,遇到种种的场景和问题,提出的解决方案和思路,沉淀下来,设计模式是解决具体问题的套路 设计模式六大原则:面向对象语言开发过程中,推荐的一些指导性原则,这些是没有明确的招数的,而且也经常被忽视或者违背! ? 一:单一职责原则(Single Responsibility Principle) 单一职责原则就是一个类只负责一件事儿,面向对象语言开发,类就是一个最基本的单位,单一职责的原则就是封装的粒度,主要关注的单个类实现的功能 比如我们下面的例子 1 /// <summary> 2 /// 封装 3 /// 动物类 4 /// 简单意味着稳定 5 /// </summary> 6 public class Animal 7 { 8 private string _Name = null; 9 public Animal(string name) 10 { 11 this._Name = name; 12 } 13 14 //应该拆分了 15 public void Action() 16 { 17 if (this._Name.Equals("鸡")) 18 Console.WriteLine($"{this._Name} flying"); 19 else if (this._Name.Equals("牛")) 20 Console.WriteLine($"{this._Name} walking"); 21 else if (this._Name.Equals("鱼")) 22 Console.WriteLine($"{this._Name} Swimming"); 23 else if (this._Name.Equals("蚯蚓")) 24 Console.WriteLine($"{this._Name} Crawling"); 25 } 26 } 我们声明一个动物,但是每个动物的action是不一样的,顺着我们的思维模式,我们会在action中增加对应的if来判断,不同的动物有不同的动作, 类似于这样的,在一个方法中写分支判断,然后执行不同的逻辑,这就违背了单一职责原则,但是其实我们想要的功能完全能实现,如果种类比较少且不变的情况下,我们完全可以这样操作,但是如果种类比较多且经常容易发生改变,那我们这样写就有很大的隐患,因为其中的改变有可能会影响到其它的。 我们可以对其进行改变,比如我们可以先创建一个基类 1 public abstract class AbstractAnimal 2 { 3 protected string _Name = null; 4 public AbstractAnimal(string name) 5 { 6 this._Name = name; 7 } 8 9 public abstract void Breath(); 10 public abstract void Action(); 11 } 然后可以创建不同动物的类来继承于这个基类 public class Fish : AbstractAnimal { public Fish() : base("鱼") { } public override void Breath() { Console.WriteLine($"{base._Name} 呼吸水"); } public override void Action() { Console.WriteLine($"{base._Name} swimming"); } } public class Chicken : AbstractAnimal { public Chicken() : base("鸡") { } public override void Breath() { Console.WriteLine($"{base._Name} 呼吸空气"); } public override void Action() { Console.WriteLine($"{base._Name} flying"); } } 类似于这样的,然后在自己的类中实现自己的方法,一个类只负责自己的事情,且都比较单一,简单意味着稳定,意味着强大,这就是所谓的单一职责原则,那么究竟什么时候回使用单一职责原则呢?如果类型复杂,方法多,这样建议使用单一职责原则! 那么使用单一职责原则也有自己的弊端,具体分为以下两个方面 1:代码量的增加(拆分开类的代码明显比之前增加) 2:使用成本就是所谓的理解成本增高(调用者要晓得不同的类) 具体的单一原则分为以下五种 1:方法级别的单一职责原则:一个方法只负责一件事儿(职责分拆小方法,分支逻辑分拆) ? 二:?里氏替换原则(Liskov Substitution Principle) 任何使用基类的地方,都可以透明的使用其子类,这主要是指 继承+透明(安全,不会出现行为不一致) 继承:子类拥有父类的一切属性和行为,任何父类出现的地方,都可以用子类来代替,主要是因为: 1:父类有的,子类是必须有的(私有不继承);如果出现了子类没有的东西,那么就应该断掉继承;、 2:子类可以有自己的属性和行为,但是子类出现的地方,父类不一定能代替 3:父类实现的东西,子类就不要再写了,(就是不要new隐藏),如果想修改父类的行为,通过abstract/virtual 举个例子: 1 public class People 2 { 3 public int Id { get; set; } 4 public string Name { get; set; } 5 7 public void Traditional() 8 { 9 Console.WriteLine("仁义礼智信 温良恭俭让 "); 10 } 11 } 12 13 public class Chinese : People 14 { 15 public string Kuaizi { get; set; } 16 public void SayHi() 17 { 18 Console.WriteLine("早上好,吃了吗?"); 19 } 20 21 } 22 23 public class Hubei : Chinese 24 { 25 public string Majiang { get; set; } 26 public new void SayHi() 27 { 28 Console.WriteLine("早上好,过早了么?"); 29 } 30 } 调用的时候: { Chinese people = new Chinese(); people.Traditional(); people.SayHi(); } { Chinese people = new Hubei(); people.Traditional(); people.SayHi(); } { var people = new Hubei(); people.Traditional(); people.SayHi(); } 上面需要注意的是:如果是普通的方法,以左边为主,就是左边是什么类,就调用谁的普通方法(编译时决定),如果是abstract或者virtual则是以右边为主(运行时决定),所以:父类有的方法,子类就不要再写了,(就是不要new隐藏),如果想修改父类的方法,通过abstract/virtual来标识! 三:迪米特法则 也叫最少知道原则,就是:一个对象应该对其他对象保持最少的了解,只与直接的朋友通信。 他主要的职责就是关注类与类之间的交互,降低类与类之间的耦合,尽量避免依赖更多的类型 举例说明: 有一个学生类,班级类,学校类 /// <summary> /// 学生 /// </summary> public class Student { public int Id { get; set; } public string StudentName { get; set; } public int Height { private get; set; } public int Salay; public void ManageStudent() { Console.WriteLine(" {0}Manage {1} ",this.GetType().Name,this.StudentName); } } /// <summary> /// 班级 /// </summary> public class Class { public int Id { get; set; } public string ClassName { get; set; } public List<Student> StudentList { get; set; } public void ManageClass() { Console.WriteLine(" {0}Manage {1} ",this.ClassName); foreach (Student s in this.StudentList) { s.ManageStudent(); } } } 1 /// <summary> 2 /// 学校 3 /// </summary> 4 public class School 5 { 6 public int Id { get; set; } 7 public string SchoolName { get; set; } 8 public List<Class> ClassList { get; set; } 9 10 public void Manage() 11 { 12 Console.WriteLine("Manage {0}",this.GetType().Name); 13 foreach (Class c in this.ClassList) 14 { 15 //遵循了迪米特,school直接跟自己的朋友classList通讯,而不是跟自己的朋友的朋友通讯 16 c.ManageClass(); 17 18 #region 违背了迪米特法则(跟自己的朋友的朋友通讯) 19 //List<Student> studentList = c.StudentList; 20 //foreach (Student s in studentList) 21 //{ 22 // Console.WriteLine(" {0}Manage {1} ",s.GetType().Name,s.StudentName); 23 //} 24 #endregion 25 26 } 27 } 28 现在的关系是:一个学校有多个班级,每个班级有多个学生,现在学校想要管理学生,学校可以直接跟班级通讯,然后班级跟学生通讯,这就是所谓的只与直接朋友通讯,然后避免依赖更多类型(这个类型不包含:基类库BCL--框架内置) 其实类与类之间的关系可以总结为: 1:纵向:继承≈实现(最密切) 2:横向:聚合> 组合> 关联> 依赖(出现在方法内部) 依赖别人更少,也让别人了解更少,比如我们项目中经常中用到的一些访问修饰符: Private:私有 ? 其实项目中能体现迪米特法则的地方比如:三层架构(UI-BLL-DAL),还有我们习惯创建的中间层(UI-中间层--(调用不同的业务逻辑进行组合)),另外还有门面模式 ?另外需要注意的是:单一职责法则只关注单类的功能;迪米特法则关注的是类与类之间的联系 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |