结合unity项目开发浅谈设计模式的六大原则(二)

原创
2018/05/09 11:36
阅读数 4.3K

接着上一篇我们接着往下讲:

 

三、依赖倒置原则

定义:针对抽象编程,不要针对实现编程;高层模块不应该依赖于底层模块,两个模块都应该依赖于抽象(抽象类/接口)。高层和底层不应该直接沟通,高层底层之间,应该有一个中间层,负责两方沟通。

比如说一个中国人和一个外国人(日本人,德国人,俄罗斯人...)沟通:

中国人和外国人不直接沟通,中间需要一个翻译,中国人和外国人都依赖于翻译。

Unity 引擎是把“依赖倒置原则”玩的很溜的一款产品。

高层依赖于底层:开发游戏需要依赖于该平台的底层API。

因为编写这些游戏时,使用C#开发一个版本,稍作调整就能发布到N 个平台。

在我们发布成不同平台的游戏的时候,Unity 本身就做了一个“对接”的任务,把我们的代码里面的API,对接到该平台上相应的API。

高层和底层都依赖于抽象:我们的游戏是依赖Unity 的,各个平台的API 也是Unity 完成对接任务的。

 

四、里氏转换原则

定义:①一个软件实体如果使用的是一个父类的话,那么一定适用于其子类。而且它察觉不出父类对象和子类对象的区别。

②在软件里面,把父类都替换成它的子类,软件的行为没有变化;通俗点说,子类型必须能够替换掉它们的父类型。

从生活层面中理解里氏转换原则,一个公司的品牌就好比是一个父类,小米这个牌子就是一个父类。

小米这个品牌的产品有很多,比如:手机,电视,笔记本电脑,空气净化器......

这些产品就好比是继承了父类以后,实现的子类。

[以下三句伪代码,就是里氏转换原则在代码中最常见的体现]

小米品牌mi = new 小米手机(); ① ②

小米手机m5 = new 小米手机(); ②

小米手机m4 = (小米手机)mi; ③

切入点:

①子类对象可以直接赋值给父类变量;

理解:使用小米手机的用户就是小米公司的用户。

②子类对象可以调用父类中的成员,但是父类对象永远只能调用自己的成员;

理解:小米手机可以打电话,还能能使用小米公司的售后服务;但是小米公司不能打电话,它只能折腾自己的用户体验,设计理念,品牌定位,营销策略......

③如果父类对象中装的是子类对象,可以将这个父类对象强转为子类对象;

理解:小米公司开新产品发布会-->小米6 手机发布会。

 

从unity引擎作为切入点理解:Unity 引擎是一个父类;

Unity4.x,Unity5.x,Unity2017.x 都是这个父类下的子类。本身具备父类的功能,同时又都有自己的新功能。

 

五、迪米特原则(又叫最少知识/知道原则)

定义:①如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。

如果其中一个类需要调用另外一个类的某一个方法的话,可以通过第三者转发这个调用。

②一个对象应当对其他对象有尽可能少的了解。

 

例如:普通人,银行,银行工作人

在现实生活中,我们普通人不需要了解银行的各种体系规章制度,当我们普通人和银行发生业务关系的时候,我们面对的是银行的工作人员。工作人员完成了普通人与银行的沟通。

而在编程中,普通人,银行,银行工作人员,会表现成三个类。

普通人与银行这两个类是完全独立的,由银行工作人员这个类,完成二者的沟通。

当普通人或者银行发生了代码逻辑改变,只会影响到中间的工作人员。

但是如果普通人和银行直接沟通,这样耦合度就提高了,降低了普通人以及银行这两个类的复用性[普通人可能还需要和其他几十个类似于银行的机构沟通]。

 

1.编程中的切入点

①在类的结构设计上,每一个类都应当尽量降低成员的访问权限。

Unity 项目开发,不要使用public 公开字段,然后面板拖拽资源赋值这种方式。应该把字段全部private 修饰,然后public 属性公开调用。

②迪米特原则主要是强调了类与类之间的松耦合。

类与类之间的耦合度越低,越有利于代码的复用,一个处于低耦合的类被修改了,不会对有关系的类造成影响。

2.Unity 迪米特原则

 

在Untiy4.x 时代:

我们创建一个脚本,挂载到游戏物体身上,该脚本内就有一堆属性可以使用。

transform,rigidoby,light,audio,collider.......

通过这些属性,就可以直接调用当前游戏物体身上的对应的其他组件。

但是“它知道的太多了”,不管我们这个游戏物体身上有没有这些组件,这些属性都是存在的,不符合“最少知道原则”。

在Untiy5.x 时代:

这些属性98%都废弃掉了,只留了一个transform 属性,用于访问当前游戏物体身上的Transform 组件。访问其他的组件,必须先获取,再访问。

 

六、接口隔离原则(这里默认了解面向对象的继承,以及接口等相关语法格式)

定义:①客户端不应该依赖它不需要的接口;

②一个类对另一个类的依赖应该建立在最小的接口上。

 

公司内有很多部门,比如:开发部,业务部,财务部等等,每个部门内都有N个员工在工作。现在我把员工要做的事情,定义成一个接口,所有员工都实现这个接口去做事情。

这个接口中定义的事情有:

工资计算,账务管理,客户扩展,客户维护,产品推销,程序开发,软件维护。

所有的员工都实现这个接口,去做事情。现在问题就出现了,不管是哪个部门的员工,在实现了这个接口后,都有很多事情是不需要自己去做的。

当前这个接口就比较臃肿,我们需要对接口进行“功能隔离”:

财务部员工接口:

工资计算,账务管理;

业务部员工接口:

客户扩展,客户维护,产品推销;

开发部员工接口:

程序开发,软件维护;

这样对接口功能隔离,细分成不同部门的职责功能接口,不管是现有的员工,还是以后新加入的员工,只需要实现自己部门对应的接口即可。

 

1.切入点

接口要尽量小。

在定义接口的时候,接口内的方法要尽量的少,避免接口过于臃肿。

一个类由于功能上的需求,需要实现一个接口,要保证该接口内所有的方法,都是该类所需要的。

 

2.Unity 接口隔离原则

比如UGUI 中,就有很多接口可以用于对UI 游戏物体进行功能扩展。

UGUI 中的UI 事件,我们在编写UI 控制脚本时,在继承了Mono 行为类之后,还可以实现N 个UI 事件接口[Interface]。这里涉及到的事件接口,它们的定义就是准守了接口隔离原则。

展开阅读全文
打赏
2
7 收藏
分享
加载中

引用来自“生如秋叶”的评论

“把父类都替换成它的子类,软件的行为没有变化“ 设计上,不正式通过子类的区别来应对变化的场景吗

引用来自“coding_”的评论

小米品牌mi = new 小米手机();
小米手机m5 = new 小米手机();
我们可以将”小米品牌“看作一个基类,“小米手机m5”是继承“小米品牌”更为具体的子类,将父类“ 小米品牌”替换成子类“小米手机m5”,对整个软件行为完全没有影响,如你所说在设计上我们是通过子类的区别来应对变化的场景,所以我们都知道可以将父类都替换成它的子类,却不能将子类替换成它的父类。所以你理解的矛盾冲突点在哪里呢?
我也举个例子吧。
LogProvider = new WinEventLogProvider();
LogProvider = new DBLogProvider();
LogProvider = new FileLogProvider();
LogProvider可以是一个抽象父类,三个不同子类分别实现了把日志信息输出到不同的设备上,这算不算对 ‘软件行为’ 产生影响呢?
2018/05/22 17:28
回复
举报

引用来自“生如秋叶”的评论

“把父类都替换成它的子类,软件的行为没有变化“ 设计上,不正式通过子类的区别来应对变化的场景吗

引用来自“coding_”的评论

小米品牌mi = new 小米手机();
小米手机m5 = new 小米手机();
我们可以将”小米品牌“看作一个基类,“小米手机m5”是继承“小米品牌”更为具体的子类,将父类“ 小米品牌”替换成子类“小米手机m5”,对整个软件行为完全没有影响,如你所说在设计上我们是通过子类的区别来应对变化的场景,所以我们都知道可以将父类都替换成它的子类,却不能将子类替换成它的父类。所以你理解的矛盾冲突点在哪里呢?
我一般通过不同的子类来改变软件的行为,以适应不同的环境,这似乎与 ‘软件的行为没有变化’ 是相反的
2018/05/22 17:23
回复
举报
coding_博主

引用来自“生如秋叶”的评论

“把父类都替换成它的子类,软件的行为没有变化“ 设计上,不正式通过子类的区别来应对变化的场景吗
小米品牌mi = new 小米手机();
小米手机m5 = new 小米手机();
我们可以将”小米品牌“看作一个基类,“小米手机m5”是继承“小米品牌”更为具体的子类,将父类“ 小米品牌”替换成子类“小米手机m5”,对整个软件行为完全没有影响,如你所说在设计上我们是通过子类的区别来应对变化的场景,所以我们都知道可以将父类都替换成它的子类,却不能将子类替换成它的父类。所以你理解的矛盾冲突点在哪里呢?
2018/05/22 16:23
回复
举报
“把父类都替换成它的子类,软件的行为没有变化“ 设计上,不正式通过子类的区别来应对变化的场景吗
2018/05/12 09:47
回复
举报
更多评论
打赏
4 评论
7 收藏
2
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部