• 六大设计原则二


    依赖倒置原则

    依赖倒置原则:上层模块不应该依赖于低层模块,二者应该通过抽象依赖,就是说应该依赖于抽象,而不是依赖于细节,面向抽象编程

    看下面的代码:

    学生类:

     public class Student
        {
           
            public int Id { get; set; }
            public string Name { get; set; } 
    
            public void PlayiPhone(iPhone phone)
            {
                Console.WriteLine("这里是{0}", this.Name);
                phone.Call();
                phone.Text();
            }
    
            public void PlayLumia(Lumia phone)
            {
                Console.WriteLine("这里是{0}", this.Name);
                phone.Call();
                phone.Text();
            }
        }

    手机抽象类:

    public abstract class AbstractPhone
        {
            public int Id { get; set; }
            public string Branch { get; set; }
            public abstract void Call();
            public abstract void Text();
        }

    各种手机类:

       /// <summary>
        /// iPhone
        /// </summary>
        public class iPhone : AbstractPhone
        {
            public override void Call()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
            public override void Text()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
        }
    
    public class Lumia : AbstractPhone
        {
            public override void Call()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
            public override void Text()
            {
                Console.WriteLine("User {0} Text", this.GetType().Name);
            }
    
            public void New()
            { }
        }

    调用:

     public class DIPShow
        {
            public static void Show()
            {
                Console.WriteLine("**************DIPShow***************");
                //Student 为上层  手机为低层  因为学生要用手机,所以学生是处于高层的
                Student student = new Student()
                {
                    Id = 191,
                    Name = "候鸟班长"
                }; 
    
                {
                    iPhone phone = new iPhone();
                    student.PlayiPhone(phone);
                }
                {
                    Lumia phone = new Lumia();
                    student.PlayLumia(phone);
                }
            }
        }

     从上面的代码逻辑中我们可以得知,Student 为上层,手机为低层  因为学生要用手机,所以学生是处于高层的。依赖倒置原则又要求我们说高层不能直接依赖于底层,二者要通过抽象进行依赖,现在的代码也能实现功能,但是后期如果说要增加不同的手机类别的话,在学生类中,就要不断改动学生类,增加学生类中使用手机的方法,此时手机和学生是依赖于细节的,所以我们需要将二者依赖于抽象,这样的话后期不管增加多少中手机品类都不用更改学生类,因为手机的变化本来就不应该和学生有联系,现在的耦合很严重,改动如下:

    学生类:

     public class Student
        {
            private AbstractPhone phone = null;
            public Student(AbstractPhone phone)
            {
                this.phone = phone;
            }
            public int Id { get; set; }
            public string Name { get; set; }
            public void Play()
            {
                Console.WriteLine("这里是{0}", this.Name);
                this.phone.Call();
                this.phone.Text();
            }
     
        }

    调用:

     public class DIPShow
        {
            public static void Show()
            {
                Console.WriteLine("**************DIPShow***************");
                //Student 为上层  手机为低层  因为学生要用手机,所以学生是处于高层的
                Student student = new Student(new iPhone())
                {
                    Id = 191,
                    Name = "候鸟班长"
                }; 
                student.Play(); 
            }
        }

    这样就实现依赖于抽象,耦合降低了。

     如果你的东西根本不会变化了,那就不需要考虑依赖倒置原则。

    好处:扩展性更高了,

    接口隔离原则

    接口隔离原则:客户端不应该依赖它不需要的接口; 一个类对另一个类的依赖应该建立在最小的接口上;或者说实现一个接口的时候,只需要自己必须的功能。

    接口就是作为一个约束,必须实现全部的接口。

    看下面的方法,手机继承了一个基类,这个基类是作为手机存在必须要实现存在的功能,是作为这个物品本质上存在的属性和行为,但是手机也有不同的,也存在不同的功能,所以我们可以通过接口来定义并实现它们:

      public abstract class AbstractPhone
        {
            public int Id { get; set; }
            public string Branch { get; set; }
            public abstract void Call();
            public abstract void Text();
        }
    
        /// <summary>
        /// 一个大而全的接口
        /// </summary>
        public interface IExtend
        {
            void Photo();
            void Online();
            void Game();
            void Record();
            void Movie();
            void Map();
            void Pay();
        }

    华为手机:

       public class Honor : AbstractPhone, IExtend
        {
            public override void Call()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
    
            public override void Text()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
    
            public void Photo()
            {
                Console.WriteLine("User {0} Photo", this.GetType().Name);
            }
    
            public void Online()
            {
                Console.WriteLine("User {0} Online", this.GetType().Name);
            }
    
            public void Game()
            {
                Console.WriteLine("User {0} Game", this.GetType().Name);
            }
    
            public void Map()
            {
                Console.WriteLine("User {0} Map", this.GetType().Name);
            }
    
            public void Pay()
            {
                Console.WriteLine("User {0} Pay", this.GetType().Name);
            }
    
            public void Record()
            {
                Console.WriteLine("User {0} Record", this.GetType().Name);
            }
    
            public void Movie()
            {
                Console.WriteLine("User {0} Movie", this.GetType().Name);
            }
        }

    IPhone:

     /// <summary>
        /// OldMan 老人机
        /// </summary>
        public class OldMan : AbstractPhone, IExtend
        {
            public override void Call()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
            public override void Text()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
    
            public void Photo()
            {
                Console.WriteLine("User {0} Photo", this.GetType().Name);
            }
    
            public void Online()
            {
                Console.WriteLine("User {0} Online", this.GetType().Name);
            }
    
            public void Game()
            {
                Console.WriteLine("User {0} Game", this.GetType().Name);
            }
    
            public void Map()
            {
                Console.WriteLine("User {0} Map", this.GetType().Name);
            }
    
            public void Pay()
            {
                Console.WriteLine("User {0} Pay", this.GetType().Name);
            }
    
            public void Record()
            {
                Console.WriteLine("User {0} Record", this.GetType().Name);
            }
    
            public void Movie()
            {
                Console.WriteLine("User {0} Movie", this.GetType().Name);
            }
        }

    但是现在有一个问题,接口作为一个约束,必须要实现它的所有方法,但是老人机没办法全部实现的,因为老人机没有导航功能,也没有支付功能等,IExtend接口功能太全了,所以我们应该拆分一下,保证它的灵活性。接口是能够多实现的,但是继承只能单继承。

        /// <summary>
        ///  
        /// </summary>
        public interface IExtend
        {
            void Photo();
            void Online();
            void Game();
          
        }
    
        public interface IExtendAdvanced
        {
            void Record();
            void Movie();
            void Map();
            void Pay();
        }

    手机类:

     /// <summary>
        /// iPhone
        /// </summary>
        public class iPhone : AbstractPhone, IExtend, IExtendAdvanced
        {
            public override void Call()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
            public override void Text()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
    
            public void Photo()
            {
                Console.WriteLine("User {0} Photo", this.GetType().Name);
            }
    
            public void Online()
            {
                Console.WriteLine("User {0} Online", this.GetType().Name);
            }
    
            public void Game()
            {
                Console.WriteLine("User {0} Game", this.GetType().Name);
            }
    
            public void Map()
            {
                Console.WriteLine("User {0} Map", this.GetType().Name);
            }
    
            public void Pay()
            {
                Console.WriteLine("User {0} Pay", this.GetType().Name);
            }
    
            public void Record()
            {
                Console.WriteLine("User {0} Record", this.GetType().Name);
            }
    
            public void Movie()
            {
                Console.WriteLine("User {0} Movie", this.GetType().Name);
            }
        }
    
        /// <summary>
        /// OldMan 老人机
        /// </summary>
        public class OldMan : AbstractPhone, IExtend 
        {
            public override void Call()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
            public override void Text()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
    
            public void Photo()
            {
                Console.WriteLine("User {0} Photo", this.GetType().Name);
            }
    
            public void Online()
            {
                Console.WriteLine("User {0} Online", this.GetType().Name);
            }
    
            public void Game()
            {
                Console.WriteLine("User {0} Game", this.GetType().Name);
            } 
        }

    比如说,我又新加了一个相机,相机默认只能拍照和上网,我再次进行接口的拆分:

      /// <summary>
        ///  
        /// </summary>
        public interface IExtend
        { 
            void Game(); 
        }
    
        public interface IExtendAdvanced
        {
            void Record();
            void Movie();
            void Map();
            void Pay();
        }
         /// <summary>
         /// 拆分出来的 相机所具有的方法 IExtend接口方法又少了
         /// </summary>
        public interface IExtendPhontography
        {
            void Photo();
            void Online();
        }

     手机相机类:

     /// <summary>
        /// iPhone
        /// </summary>
        public class iPhone : AbstractPhone, IExtend, IExtendAdvanced, IExtendPhontography
        {
            public override void Call()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
            public override void Text()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
    
            public void Photo()
            {
                Console.WriteLine("User {0} Photo", this.GetType().Name);
            }
    
            public void Online()
            {
                Console.WriteLine("User {0} Online", this.GetType().Name);
            }
    
            public void Game()
            {
                Console.WriteLine("User {0} Game", this.GetType().Name);
            }
    
            public void Map()
            {
                Console.WriteLine("User {0} Map", this.GetType().Name);
            }
    
            public void Pay()
            {
                Console.WriteLine("User {0} Pay", this.GetType().Name);
            }
    
            public void Record()
            {
                Console.WriteLine("User {0} Record", this.GetType().Name);
            }
    
            public void Movie()
            {
                Console.WriteLine("User {0} Movie", this.GetType().Name);
            }
        }
    
        /// <summary>
        /// OldMan 老人机
        /// </summary>
        public class OldMan : AbstractPhone, IExtend
        {
            public override void Call()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
            public override void Text()
            {
                Console.WriteLine("User {0} Call", this.GetType().Name);
            }
    
            public void Photo()
            {
                Console.WriteLine("User {0} Photo", this.GetType().Name);
            }
    
            public void Online()
            {
                Console.WriteLine("User {0} Online", this.GetType().Name);
            }
    
            public void Game()
            {
                Console.WriteLine("User {0} Game", this.GetType().Name);
            }
        }
        /// <summary>
        ///相机 假设相机只能拍照和上网
        /// </summary>
        public class Camera : IExtendPhontography
        {
            /// <summary>
            /// 拍照
            /// </summary>
            public void Photo()
            {
                Console.WriteLine("User {0} Photo", this.GetType().Name);
            }
            /// <summary>
            /// 录音
            /// </summary>
            public void Online()
            {
                Console.WriteLine("User {0} Online", this.GetType().Name);
            }
    
        }

     为什么分要对接口进行拆分呢?比如说新进相机之后,我不再拆分IExtend接口,我新建一个接口IExtendPhontographyTest,IExtend接口不动:

     /// <summary>
        ///  
        /// </summary>
        public interface IExtend
        { 
            void Game(); 
            void Photo();
            void Online();
        }
    
        public interface IExtendAdvanced
        {
            void Record();
            void Movie();
            void Map();
            void Pay();
        }
         /// <summary>
         /// 拆分出来的 相机所具有的方法 IExtend接口方法又少了
         /// </summary>
        public interface IExtendPhontographyTest
        {
             void Photo();
            void Online();
        }

    实现类:

       /// <summary>
        ///相机 假设相机只能拍照和上网
        /// </summary>
        public class Camera : IExtendPhontographyTest
        {
            /// <summary>
            /// 拍照
            /// </summary>
            public void Photo()
            {
                Console.WriteLine("User {0} Photo", this.GetType().Name);
            }
            /// <summary>
            /// 录音
            /// </summary>
            public void Online()
            {
                Console.WriteLine("User {0} Online", this.GetType().Name);
            }
    
        }

    这样功能上是没问题的,但是这样的话就少了复用性,但是如果使用拆分接口的形式的话,就能够实现复用性:

         public class ISPShow
        {
            public static void Show()
            { 
                IExtendPhontography phontography = new iPhone();
                IExtendPhontography camara = new Camera();
                Photography(camara);
                Photography(phontography);
            }
             
            /// <summary>
            /// 只要是实现了这个接口IExtendPhontography的类都可以调用这个方法
            /// </summary>
            /// <param name="extend"></param>
            public static void Photography(IExtendPhontography extend)
            {
                extend.Photo();
                extend.Online();
            }
    
        }

    IPhone和camera类都实现了IExtendPhontography类,所以也都能调用这个方法,但是如果只是另外新建了一个类的话,这个方法就只能相机类能用了。 

    所以说,接口隔离原则希望我们能够尽量将接口拆分一下,保证它的灵活性,只依赖于自己本身需要的接口,也是依赖倒置的延续,复用性更强,都是为了未来更好 的扩展开放, c#中很多封装的类都是这种形式,实现多接口比如List,Dictionary。

    最后,为什么我们要拆分接口呢?因为不能让类型实现自己没有的功能,也能让方法具备复用性。

    究竟如何设计呢?

    1 接口不能太大,否则会实现不需要的功能

    2 接口尽量的小,但是一致的功能应该在一起,也不能过度设计。

    3 接口合并:如果一个业务包含多个步骤,我们不能把步骤都暴露,而是提供一个入口即可。比如手机定位,定位肯定要有很多步骤,不能都开放出来,只留出一个定位的接口就行。

    开闭原则

    开闭原则:对扩展开发,对修改关闭。如果有功能扩展变化的需求,希望是增加而不是修改 ,尽量不影响之前的功能

    IExtendPhontographyTest
  • 相关阅读:
    amd
    富文本编辑器
    css module
    uc浏览器调试
    mysql利用sql语句将查询结果导出
    自启程序为何自启失败?
    nginx4层代理ssh服务
    创建SFTP用户并指定访问目录 Linux
    01月04日17:15:40 学习进度笔记
    01月04日10:39:23总结
  • 原文地址:https://www.cnblogs.com/anjingdian/p/15333353.html
Copyright © 2020-2023  润新知