zoukankan      html  css  js  c++  java
  • 禁止未发布的博文上首页等

    每一种模式都在说明某种一再出现的问题,并描述解决方法的核心,之后让你能够举一反三,从而解决数个类似的问题。每一种设计模式除了按照“面向对象的设计原则”加以分析设计之外,还满足:”解决一再出现的问题“、”解决问题的方案和问题核心的关键点“、”可以重复利用解决方案“这样几个要求。

      通过引入”模式“的概念,以经验积累的方式,将一些经常用来解决特定问题的”类设计“、”对象组装“加以整理并定义成一种”设计模式“。而这些设计模式让开发者在以后遇到相同的问题时,可以从中找出对应的解决方案直接使用,不必再过多地思考如何设计分析。这样不但可以减少不必要的时间花费,还可以加强软件的”稳定性“和”可维护性“。

    回到顶部
    游戏开发设计中的常见7大设计原则

      虽然标题写的是”游戏开发设计中的常见7大设计原则“,其实这些原则本来就是适用于普遍性的面向对象设计。如果软件设计人员能够充分了解这些设计原则并且加以利用,那么就可以让实现出来的系统更加稳定、容易维护、具有更好的拓展性。

    单一职责原则(SRP)

      这个原则强调的是”当设计封装一个类时,该类应该只负责一件事“。当然,这与在类抽象化的过程中,对于该类所负责的功能有关。一个类应该只负责系统中的一个单独功能的实现,但是对于功能的划分和归属,通常也是开发过程中最困扰设计人员的问题。设计人员在一开始的时候不太容易遵循这个原则,会在项目开发的过程中,不断地向同一个类上添加功能,最后导致类过于庞大、接口过于复杂后才会发现这个问题,最后可能让整个项目过度依赖这个类,使得项目失去弹性。

      但是,只要通过不断地进行”类重构“,将类中与实现相关功能的部分抽取出来,另外封装成新的类,之后利用组合的方式,将新增的类加入到原有的类中,慢慢地就能符合类单一职责化的要求了,即项目中每一个类都只负责单一功能的实现。

    开闭原则(OCP)

      一个类应该”对拓展开放,对修改封闭“。何为对拓展开放对修改封闭呢?其实这里提到的类指的是实现系统某项功能的类。而这个功能的类,除非是修正错误,否则,当软件的开发流程进入“完工测试期”或者“上市维护期”时,对于已经测试完成或者已经上线运行的功能,就应该“关闭对修改的需求”,也就是不能再修改这个类的任何接口或者实现。

      但是,当增加系统功能的需求发生的时候,又不能置之不理,所以也必须对“功能的增加保持开放”。为了满足这个原则的要求,系统分析时就要朝向“功能接口化”的方向进行设计,将系统功能的“操作方法”向上提升,抽象化为接口,将“功能的实现”向下移到子类中。因此,在面对增加系统功能的需求时,就可以使用“增加子类”的方法来满足。具体的实现方式是:重新实现一个新的子类,或者继承就得实现类,并在新的子类中实现新增的系统功能。这样,对于旧系统的功能实现就可以保持不变(封闭),同时又对功能的新增需求保持开放。

    里氏替换原则(LSP)

      这个原则指的是“子类必须能够替换父类”。如果按照这个设计原则去实现一个有多层继承的类群组,那么其中的父类通常是“接口”或者“可被继承的类”。父类中一定包含了可被子类重新实现的方法,而客户端使用的操作接口也是由父类来定义的。客户端在使用的过程中,必须不能使用到“对象强制转型成子类”的语句,客户端也不应该知道,目前正在使用的对象是哪一个子类实现的。至于使用哪个子类对象来代替父类对象,则是由类本身的对象产生机制来决定,外籍无法得知。里氏替换原则基本上也是对于开放——封闭原则提供了一个实现的法则,说明如何设计才能保持正确的需求开放。

    依赖倒置原则(DIP)

      这个原则包含了两个主题:

    高层模块不应该依赖于低层模块,两者都应该依赖于抽象概念;
    抽象接口不应该依赖于实现,而实现应该依赖于抽象接口。
      从生活中举例来解释第一个原则主题(高层模块不应该依赖于低层模块),两者都应该依赖于抽象,可能会比单纯使用软件设计来解释更为容易,所以下面就以汽车为例进行说明。

      汽车与汽车引擎就是一个很明显违反这个原则的例子:汽车就是所谓的高层模块,当要组装一台汽车时,需要有不同的低层模块进行配合才能完成,如引擎、传统系统、轮胎、汽车骨架等,有了这些低层模块的相互配合才能完成一辆汽车的装配。但是汽车很容易被引擎系统给限定。汽油机的汽车不能加装柴油,柴油机的汽车不能加装汽油。每当汽车要加油的时候,都必须根据引擎来选择不同的加油设施,汽车因为引擎而被限定了加油的品项。虽然这是一个很难去改变的例子,但是在软件系统的设计上,反倒有很多方法可以去避免这个“高层依赖于低层”的问题,也就是将它们之间的关系反转,让低层模块按照高层模块所定义的接口去实现。

      以电脑的组成为例,位于高层的电脑定义了USB接口,而这个接口定义了硬件所需的规格及软件驱动程序的编写规范。只要任何低层模块,如储存卡、手机、U盘、读卡器等设备,凡是符合USB接口规范的,都能加入到电脑中,成为电脑的一部分。通过这个电脑的例子我们大概就可以明白如何由“高层模块定义接口”再由“底层模块遵循这个接口实现”的过程,这个过程可以让他们之前的依赖关系反转。同时,这个反转的过程也说明了第二项原则的含义:“抽象接口不应该依赖于实现,而实现应该依赖于抽象接口”。当高层模块定义了沟通接口以后,与低层模块的沟通就应该只通过接口来进行,在具体实现上,这个接口可能是以一个类的变量或者对象引用来表示的。请注意,在使用这个变量或者对象引用的过程中,不能做任何的类型转换,因为这样就限定了高层模块只能使用某一个底层模块的特定实现。而且,子类在重新实现时,都要按照接口类所定义的方法进行实现,不应该再新增其他方法,不能让高层模块有利用类型转换的方法去调用的机会。

    接口隔离原则(ISP)

      “客户端不应该被迫使用它们用不到的接口方法。”这个问题一般随着项目开发的进行而越来越明显。当项目中出现了一个负责主要功能的类,而且这个类还必须负责和其他子系统进行沟通时,针对每一个子系统的需求,主要类就必须增加对应的方法。但是,增加越多的方法就等同于增加类的接口的复杂度。因此每当要使用这个类的方法的时候,就要小心翼翼地从中选择正确的方法,无形之中增加了开发和维护的难度。通过“功能的切分”和“接口的简化”可以减少这类问题的发生,或者运用设计模式来重新规划类,也可以减少不必要的操作接口出现在类中。

    最少知识原则(LKP)

      当设计实现一个类时,这个类应该越少使用到其它类提供的功能越好。意思是,当这个类能够只靠本身的“知识”去完成功能的话,那么就相应地减少与其他对象“知识”的依赖度。这样的好处就是减少了这个类与其他类的耦合度(即依赖度),换个角度来看,就是增加了这个类被不同项目复用的可能性,提高类的重用性。

    少用继承多用组合原则

      当子类继承一个“接口类”后,新的子类就要负责重新实现接口类中所定义的方法,而且不该额外扩充接口,以符合上述多个设计原则的要求。但是,当系统想要扩充或者增加某一项功能时,让子类继承原来的实现类,却也是最容易实现的方式之一。新增的子类在继承父类后,在子类内增加想要扩充的“功能方法”并加以实现,客户端之后就能直接利用子类对象进行新增功能的调用。

      但是对于客户端而言,当下可能只是需要子类所提供的功能,对父类中一些额外方法并不感兴趣,因为这样会增加开发者挑选方法时的难度。例如,“闹钟类”可以利用继承“时钟类”的方式,获得一个“时间功能”的方法,只要子类本身再另外加上“定时提醒”的功能,就能实现“闹钟功能”的目标。当客户端使用“闹钟类”的时候,可能期待的只不过是设定闹钟时间的方法而已,对于取得当前时间的功能并没有迫切的需求。因此,从“时钟父类”继承而来的方法,对于闹钟的用户来说,可能是多余的。

      如果将设计改为在闹钟的类中声明一个类型为时钟类的“类成员”,那么就可以减少不必要的方法出现在闹钟接口上,也可以减少“闹钟类”的客户端对“时钟类”的依赖。另外,在无法使用多重继承的程序设计语言中(Java、C#等),使用组合的方式会比层层继承的方式更加容易理解和维护,并且对于类的封装也有比较好的表现方式。

    回到顶部
    总结

      以上只是面向对象设计中的7个基本的设计原则,却也是最重要的原则,只有理解了这些基础的原则之后才能继续更深入地学习GOF所提到的23种设计模式。23种设计模式并不是教条式的规则和框架,他们都是解决问题的方法的概念的呈现。一些优秀的设计方案由于种种原

  • 相关阅读:
    Undefined symbols for architecture armv7错误解决方法
    一个iOS 框架介绍:MKNetworkKit
    objective-c之各种数值
    利用openURL,在IOS应用中打开另外一个应用
    hackerrank---List Comprehensions
    LeetCode --- Plus One
    Vim学习与总结
    LeetCode --- Pascal's Triangle II
    LeetCode --- Gray Code
    LeetCode --- Two Sum
  • 原文地址:https://www.cnblogs.com/keketest/p/6936117.html
Copyright © 2011-2022 走看看