五分钟了解设计模式六大原则(下)

简介

实际上真实项目很难全部遵循,更多的时候会有一些侧重性,设计模式六大原则要能灵活应用,离不开实践的锤炼和思考,把这个真的融入到骨子里面去了,设计确实会不一样的

设计模式是什么?

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

设计模式六大原则是什么?

面向对象语言开发过程中,推荐的一些指导性原则没有明确的招数,而且也经常会被忽视/违背也是前辈总结,也是为了站在前辈的肩膀上

设计模式有哪些?

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

依赖倒置原则(Dependence Inversion Principle)

高层模块不应该依赖于低层模块,二者应该通过抽象依赖。
	{
	     //面向抽象后,不能使用子类的特别内容
	      Mi student= new Mi();
	      student.Play(phone);
          student.PlayT(phone);
	      //如果传递的是Mi,Bracelet是有的,但是方法确实不能用
	      //编译器决定了是不能用Bracelet的(dynamic/反射是可以调用的)
	
	      //不能常规调用,这个问题是解决不了的,
	      //因为面向抽象不止一个类型,用的就是通用功能;非通用的,那就不应该面向抽象
	  }
	public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }

        /// <summary>
        /// 依赖细节  高层就依赖了底层
        /// </summary>
        /// <param name="phone"></param>
        public void PlayMi(Mi phone)
        {
            Console.WriteLine("这里是{0}", this.Name);
            phone.Call();
            phone.Text();

            phone.Bracelet();//要用手环功能
        }
        public void Play(AbstractPhone phone)
        {
            Console.WriteLine("这里是{0}", this.Name);
            phone.Call();
            phone.Text();

            //phone.Bracelet();
        }
        public void PlayT<T>(T phone) where T : AbstractPhone
        {
            Console.WriteLine("这里是{0}", this.Name);
            phone.Call();
            phone.Text();
        }
    }
	public class Mi : 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 Bracelet()
        {
            Console.WriteLine("User {0} Bracelet", this.GetType().Name);
        }
    }
	public abstract class AbstractPhone
    {
        public int Id { get; set; }
        public string Branch { get; set; }
        public abstract void Call();
        public abstract void Text();
    }
像PlayMi方法就是高层直接依赖了底层。使用泛型或抽象类型就可以避免这个问题。但面向抽象后,不能使用子类的特别内容,若一定要使用可以通过反射的方式。

我们应该如何使用依赖倒置原则呢?

  1. 面向抽象,只要抽象不变,高层就不变
  2. 面向对象语言开发,就是类与类之间进行交互,如果高层直接依赖低层的细节,细节是多变的,那么低层的变化就导致上层的变化;如果层数多了,底层的修改会直接水波效应传递到最上层,一点细微的改动都会导致整个系统从下往上的修改
  3. 面向抽象,如果高层和低层没有直接依赖,而是依赖于抽象,抽象一般是稳定的,那低层细节的变化扩展就不会影响到高层,这样就能支持层内部的横向扩展,不会影响其他地方,这样的程序架构就是稳定的
  4. 依赖倒置原则(理论基础)—IOC控制反转(实践封装)—DI依赖注入(实现IOC的手段)

接口隔离原则(Interface Segregation Principle)

客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上;
	Student student = new Student()
   	{
         Id = 191,
         Name = "张三"
     };
	{
     	IExtendVideo camera = new Camera();
        student.Video(camera);
    }

    {
        IExtendHappy extend = new TV();
        student.Happy(extend);
    }
    {
        IExtendGame extend = new PSP();
        student.Happy(extend);
    }
public interface IExtend
    {
        //void Photo();
        //void Online();
        //void Game();
        void Record();
        //void Movie();
        void Map();//
        void Pay();
    }//都拆成一个方法一个接口


    //电视--上网 玩游戏
    public interface IExtendHappy : IExtendGame
    {
        void Online();
        //void Game();
    }
    //掌中游戏机:俄罗斯方块--玩游戏不能上网

    public interface IExtendGame
    {
        void Game();
    }

    public interface IExtendVideo
    {
        void Photo();
        void Movie();//打开相机--切换模式--start--Suspend--End
    }
	public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }


        public void Video(IExtendVideo extend)
        {
            extend.Photo();
            extend.Movie();
        }

        public void Happy(IExtendGame extend)
        {
            extend.Game();
        }
    }
尽量少声明大而全的接口,将接口更加细致的拆分,当然都拆成一个方法一个接口,肯定也不好!可以参考官方提供的类型例子
例如:List<> 它继承Dictionary,IList<T>  (索引相关),ICollection<T>  集合相关操作,IEnumerable<T>  迭代器foreach

我们应该如何使用接口隔离原则呢?

  1. 既不能是大而全,会强迫实现没有的东西,也会依赖自己不需要的东西
  2. 也不能一个方法一个接口,这样面向抽象也没有意义的。按照功能的密不可分来定义接口,而且应该是动态的,随着业务发展会有变化的,但是在设计的时候,要留好提前量,避免抽象的变化。这个没有标准答案,随着业务和产品来调整的。
  3. 接口需要进行合并 ()例如:Map接口 需要继承 定位/搜索/导航) 这种属于固定步骤,业务细节,尽量的内聚,在接口也不要暴露太多业务细节

开闭原则 (Open Closed Principle)

对扩展开发,对修改关闭
面向对象语言是一种静态语言,最害怕变化,会波及很多东西又会涉及到全面测试。所以最理想就是新增类,对原有代码没有改动,原有的代码才是可信的。
开闭原则只是一个目标,并没有任何的手段,也被称之为总则。其他5个原则的建议,就是为了更好的做到OCP,也就是最终的目标——减少对原有代码的改动。

我们应该如何使用开闭原则呢?

按照修改的波及来排名:
	修改现有方法 > 增加方法 > 增加类 > 增加/替换类库

修改原有的方法对项目的影响最大。替换类DLL对项目影响最小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值