六大原则

六大设计模式原则

1. 单一职责原则(Single Responsibility Principle)
2. 里氏替换原则(Liskov Substitution Principle)
3. 依赖倒置原则(Dependence Inversion Principle)
4. 接口隔离原则(Interface Segregation Principle)
5. 迪米特法则 (Law Of Demeter)
6. 开闭原则 (Open Closed Principle)

设计模式:面向对象语言开发过程中,遇到种种的场景和问题,提出的解决方案和思路,沉淀下来设计模式是解决具体问题的套路

设计模式六大原则:面向对象语言开发过程中,推荐的一些指导性原则没有明确的招数,而且也经常会被忽视/违背

一,单一职责原则(Single Responsibility Principle)

单一职责原则:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。一个类只负责一件事儿。面向对象语言开发,类是一个基本单位,单一职责原则就是封装的粒度。写分支判断,然后执行不同的逻辑,其实这就违背了单一职责原则,但是功能是可以实现的。

举例说明:

 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         /// <summary>
14         /// 这个方法就挺不稳定,经常各种分支变化经常修改
15         /// </summary>
16         public void Breath()
17         {
18             if (this._Name.Equals(""))
19                 Console.WriteLine($"{this._Name} 呼吸空气");
20             else if (this._Name.Equals(""))
21                 Console.WriteLine($"{this._Name} 呼吸空气");
22             else if (this._Name.Equals(""))
23                 Console.WriteLine($"{this._Name} 呼吸水");
24             else if (this._Name.Equals("蚯蚓"))
25                 Console.WriteLine($"{this._Name} 呼吸泥土");
26         }
27         //BreathChicken  BreathFish
28 
29         //应该拆分了
30         public void Action()
31         {
32             if (this._Name.Equals(""))
33                 Console.WriteLine($"{this._Name} flying");
34             else if (this._Name.Equals(""))
35                 Console.WriteLine($"{this._Name} walking");
36             else if (this._Name.Equals(""))
37                 Console.WriteLine($"{this._Name} Swimming");
38             else if (this._Name.Equals("蚯蚓"))
39                 Console.WriteLine($"{this._Name} Crawling");
40         }
41     }

我们声明一个动物,但是每个动物的action是不一样的,顺着我们的思维模式,我们会在action中增加对应的if来判断,不同的动物有不同的动作,

类似于这样的,在一个方法中写分支判断,然后执行不同的逻辑,这就违背了单一职责原则,但是其实我们想要的功能完全能实现,如果种类比较少且不变的情况下,我们完全可以这样操作,但是如果种类比较多且经常容易发生改变,那我们这样写就有很大的隐患,因为其中的改变有可能会影响到其它的。

我们可以对其进行改变,比如我们可以先创建一个基类:

 public abstract class AbstractAnimal
    {
        protected string _Name = null;
        public AbstractAnimal(string name)
        {
            this._Name = name;
        }

        public abstract void Breath();//呼吸的方法
        public abstract void Action();//执行的动作
    }

然后可以创建不同动物的类来继承于这个基类:

public class Chicken : AbstractAnimal
    {
        public Chicken(string name) : base(name)
        {
        }

        public Chicken() : base("")
        {
        }

        public override void Breath()
        {
            Console.WriteLine($"{base._Name} 呼吸空气");
        }
        public override void Action()
        {
            Console.WriteLine($"{base._Name} flying");
        }
    }
 public class Fish : AbstractAnimal
    {
        public Fish() : base("")
        {
        }

        public override void Breath()
        {
            Console.WriteLine($"{base._Name} 呼吸水");
        }
        public override void Action()
        {
            Console.WriteLine($"{base._Name} swimming");
        }
    }

类似于上面的这两个类,每个类中实现自己的方法,一个类只负责自己的事情,且都比较单一,简单意味着稳定,意味着强大,这就是所谓的单一职责原则,那么究竟什么时候回使用单一职责原则呢?如果类型复杂,方法多,这样建议使用单一职责原则!

使用单一职责原则有自己的利弊:

1.拆分成父类+子类 每个类很简单,简单意味着稳定 意味着强大。

2. 拆分后,也会造成代码量的增加。

3.类多了,使用成本也高(理解成本)。与没有拆分前 都是放在一个类或者方法中实现,只用关注一个类;而拆分后,需要关注的类变多了,需要理解每个类的内容才能方便使用。

单一职责分为以下五种:

方法级别的单一职责原则:一个方法只负责一件事儿(职责分拆小方法,分支逻辑分拆)。
类级别的单一职责原则:一个类只负责一件事儿。
类库级别的单一职责原则:一个类库应该职责清晰。
项目级别的单一职责原则:一个项目应该职责清晰(客户端/管理后台/后台服务/定时任务/分布式引擎)。
系统级别的单一职责原则:为通用功能拆分系统(IP定位/日志/在线统计)。

二. 里氏替换原则(Liskov Substitution Principle)

任何使用基类的地方,都可以透明的使用其子类,这主要是指 继承+透明(安全,不会出现行为不一致)

继承:子类拥有父类的一切属性和行为,任何父类出现的地方,都可以用子类来代替,主要是因为:

1:父类有的,子类是必须有的(私有不继承);如果出现了子类没有的东西,那么就应该断掉继承;、

2:子类可以有自己的属性和行为,但是子类出现的地方,父类不一定能代替

3:父类实现的东西,子类就不要再写了,(就是不要new隐藏),如果想修改父类的行为,通过abstract/virtual

举例:

 public class People
    {
        public int Id { get; set; }
        public string Name { get; set; }

        //abstract void Eat();
        public void Traditional()
        {
            Console.WriteLine("仁义礼智信 温良恭俭让 ");
        }
    }

    public class Chinese : People
    {
        public string Kuaizi { get; set; }
        public void SayHi()
        {
            Console.WriteLine("早上好,吃了吗?");
        }

    }

    public class Hubei : Chinese
    {
        public string Majiang { get; set; }
        public new void SayHi()
        {
            Console.WriteLine("早上好,过早了么?");
        }
    }

    

调用:

            {
                //People people = new Chinese();
                Chinese people = new Chinese();
                people.Traditional();
                people.SayHi();
            }
            {
                Chinese people = new Hubei();
                people.Traditional();
                people.SayHi();

            }
            {
                var people = new Hubei();
                people.Traditional();
                people.SayHi();
            }

比如:现在有个日本人 ,日本人是没有传统的,但是日本人是人。如果日本人也继承people类;


 1   public class Japanese : People
 2     {
 3         //public int Id { get; set; }
 4         //public string Name { get; set; }
 5         //public new void Traditional()
 6         //{
 7         //    Console.WriteLine("忍者精神 ");
 8         //throw new Exception();
 9         //}
10         //Traditional也会继承 但是Japanese又没有Traditional
11         public void Ninja()
12         {
13             Console.WriteLine("忍者精神 ");
14         }
15 
16     }

可以通过抛出异常的方式解决 日本人没有传统这个方法,或者是新建一个类,日本人继承新的类,或者是在方法前加 new 关键字来隐藏 public new void Traditional();

  public class Animal//让日本人继承自Animal
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

  

 
 1  public class Japanese : Animal
 2     {
 3         public int Id { get; set; }
 4         public string Name { get; set; }
 5         public new void Traditional()
 6         {
 7             Console.WriteLine("忍者精神 ");
 8             throw new Exception();
 9         }
10         //Traditional也会继承 但是Japanese又没有Traditional
11         public void Ninja()
12         {
13             Console.WriteLine("忍者精神 ");
14         }
15 
16     }

 注意的是:如果是普通的方法,以左边为主,就是左边是什么类,就调用谁的普通方法(编译时决定),如果是abstract或者virtual则是以右边为主(运行时决定),所以:父类有的方法,子类就不要再写了,(就是不要new隐藏),如果想修改父类的方法,通过abstract/virtual来标识!

三,迪米特法则 Law Of Demeter

迪米特法则:最少知道原则,一个对象应该对其他对象保持最少的了解。只与直接的朋友通信。

举例:

 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               
16                 c.ManageClass();//1 遵循了迪米特
17                 //List<Student> studentList = c.StudentList;
18                 //foreach (Student s in studentList)
19                 //{
20                 //    Console.WriteLine(" {0}Manage {1} ", s.GetType().Name, s.StudentName);
21                 //}//2 违背了迪米特法则
22 
23             }
24         }
25 
26 
27     }


 1  /// <summary>
 2     /// 班级
 3     /// </summary>
 4     public class Class
 5     {
 6         public int Id { get; set; }
 7         public string ClassName { get; set; }
 8 
 9         public List<Student> StudentList { get; set; }
10 
11 
12         public void ManageClass()
13         {
14             Console.WriteLine(" {0}Manage {1} ", this.GetType().Name, this.ClassName);
15             foreach (Student s in this.StudentList)
16             {
17                 s.ManageStudent();
18                 //Console.WriteLine(" {0}Manage {1} ", s.GetType().Name, s.StudentName);
19             }
20 
21         }
22 
23 
24     }
 1   /// <summary>
 2     /// 学生
 3     /// </summary>
 4     public class Student
 5     {
 6         public int Id { get; set; }
 7         public string StudentName { get; set; }
 8         public int Height { private get; set; }
 9 
10         public int Salay;
11 
12         public void ManageStudent()
13         {
14             Console.WriteLine(" {0}Manage {1} ", this.GetType().Name, this.StudentName);
15         }
16


 类与类之间的关系: 

 纵向:继承≈实现(最密切)

 横向:聚合> 组合> 关联> 依赖(出现在方法内部)
 高内聚低耦合
 迪米特法则,降低类与类之间的耦合 只与直接的朋友通信,就是要尽量避免依赖更多类型  基类库(BCL--框架内置的)的类型除外
 迪米特,也会增加一些成本,工作中有时候会去造一个中介/中间层,门面模式 中介者模式 分层封装 
 
 项目中应用场景:上层UI下订单---订单系统&支付系统&仓储&物流  门面模式--上层交互门面--门面依赖子系统  三层架构:UI---BLL---DAL
 去掉内部依赖
 降低访问修饰符权限
 private
 protected
 internal
 protected internal 子类或者同类库
 public

 迪米特,依赖别人更少,让别人了解更少

 
原文地址:https://www.cnblogs.com/super-xi-xi/p/10213649.html