本文主要是介绍五分钟了解设计模式六大原则(下),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 简介
- 设计模式是什么?
- 设计模式六大原则是什么?
- 设计模式有哪些?
- 依赖倒置原则(Dependence Inversion Principle)
- 我们应该如何使用依赖倒置原则呢?
- 接口隔离原则(Interface Segregation Principle)
- 我们应该如何使用接口隔离原则呢?
- 开闭原则 (Open Closed Principle)
- 我们应该如何使用开闭原则呢?
简介
实际上真实项目很难全部遵循,更多的时候会有一些侧重性,设计模式六大原则要能灵活应用,离不开实践的锤炼和思考,把这个真的融入到骨子里面去了,设计确实会不一样的
设计模式是什么?
面向对象语言开发过程中,遇到种种的场景和问题,提出的解决方案和思路,沉淀下来设计模式是解决具体问题的套路
设计模式六大原则是什么?
面向对象语言开发过程中,推荐的一些指导性原则没有明确的招数,而且也经常会被忽视/违背也是前辈总结,也是为了站在前辈的肩膀上
设计模式有哪些?
- 单一职责原则(Single Responsibility Principle)
- 里氏替换原则(Liskov Substitution Principle)
- 迪米特法则 (Law Of Demeter)
- 依赖倒置原则(Dependence Inversion Principle)
- 接口隔离原则(Interface Segregation Principle)
- 开闭原则 (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方法就是高层直接依赖了底层。使用泛型或抽象类型就可以避免这个问题。但面向抽象后,不能使用子类的特别内容,若一定要使用可以通过反射的方式。
我们应该如何使用依赖倒置原则呢?
- 面向抽象,只要抽象不变,高层就不变
- 面向对象语言开发,就是类与类之间进行交互,如果高层直接依赖低层的细节,细节是多变的,那么低层的变化就导致上层的变化;如果层数多了,底层的修改会直接水波效应传递到最上层,一点细微的改动都会导致整个系统从下往上的修改
- 面向抽象,如果高层和低层没有直接依赖,而是依赖于抽象,抽象一般是稳定的,那低层细节的变化扩展就不会影响到高层,这样就能支持层内部的横向扩展,不会影响其他地方,这样的程序架构就是稳定的
- 依赖倒置原则(理论基础)—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
我们应该如何使用接口隔离原则呢?
- 既不能是大而全,会强迫实现没有的东西,也会依赖自己不需要的东西
- 也不能一个方法一个接口,这样面向抽象也没有意义的。按照功能的密不可分来定义接口,而且应该是动态的,随着业务发展会有变化的,但是在设计的时候,要留好提前量,避免抽象的变化。这个没有标准答案,随着业务和产品来调整的。
- 接口需要进行合并 ()例如:Map接口 需要继承 定位/搜索/导航) 这种属于固定步骤,业务细节,尽量的内聚,在接口也不要暴露太多业务细节
开闭原则 (Open Closed Principle)
对扩展开发,对修改关闭
面向对象语言是一种静态语言,最害怕变化,会波及很多东西又会涉及到全面测试。所以最理想就是新增类,对原有代码没有改动,原有的代码才是可信的。
开闭原则只是一个目标,并没有任何的手段,也被称之为总则。其他5个原则的建议,就是为了更好的做到OCP,也就是最终的目标——减少对原有代码的改动。
我们应该如何使用开闭原则呢?
按照修改的波及来排名:修改现有方法 > 增加方法 > 增加类 > 增加/替换类库
修改原有的方法对项目的影响最大。替换类DLL对项目影响最小。
这篇关于五分钟了解设计模式六大原则(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!