GRASP(General Responsibility Assignment Software Pattern)是通用职责分配软件设计模式。
它由《UML和模式应用》(Applying UML and Patterns)一书做者Craig Larman提出。在面向对象设计的过程当中通常的通用方式是构思对象的职责、角色和协做。一般来讲,咱们在编码过程当中先分析问题域,从中抽象出对象解决问题。简单的面向对象和优良的面向对象设计的区别在于将如何更合理的划分对象的角色,给对象赋予合理的职责以及对象之间的交互关系。html
在我所理解的GRASP九大原则、SOLID七大原则、GOF23种设计模式这三类设计原则模式中。GRASP处于最上层,SOLID基于它再进一步细化阐述,GOF再根据这些原则进一步的概括出更具体的模式。
GoF模式是针对特定问题而提出的解决方案,而GRASP站在一个更高的角度来看待面向对象软件的设计,它是GoF设计模式的基础。GRASP是对象职责分配的基本原则,其核心思想是职责分配,用职责设计对象。数据库
若是某个类拥有执行某个职责所必需的的信息的话,那么将这个职责分配给这个类。编程
当咱们不肯定某个职责该分配给类A仍是类B的时候,咱们能够遵循这个原则。这个设计原则和单一设计原则不一样,单一职责原则考虑的是单个类中的职责是否都属于一类职责。而信息专家模式考虑则是该把该同一类职责放进类A仍是类B中。假设咱们有一个长方形Rectangle类(类中有width和height属性)和一个Measure类,咱们应该把getArea()方法放进Rectangle中去,仍是将width和height参数传给Measure类,在Measure中实现getArea()呢?依照该准则,既然Rectangle方法已经有了实现getArea()所必须的属性的话,那么就把该把getArea()方法放进Retangle类中。同理若是有一个计算属性呢?假设是长宽高比例widthHeightRatio的话,也遵循该原则。==这个原则和DDD设计思想当中的充血模型是一致的,你们能够了解一下。==设计模式
若是符合下面的一个或者多个条件,则可将建立类A实例的职责分配给类B编码
在面向对象的设计当中,没法避免去建立对象。假设对象B建立对象A,那么对象B就产生了与对象A的耦合。而这种耦合是没法消除的,即便你将建立对象A的职责分配给对象C,这种耦合仍是存在的,只是从对象B转移到对象C上,系统内仍是依然存在这个耦合,没法避免。那么当咱们没法消除耦合的时候,咱们应该考虑的是如何下降这个耦合的耦合度。这个原则给出了指导方针。以上的几个条件潜在的代表了,其实B已经对A有了耦合,既然B已经存在了对A的耦合,那么咱们不妨再将建立A的职责分配给他。这样分配的话,系统内仅存在一个A与B的耦合。若是将建立A的职责分配给C的话,那么系统内就会存在B与A(B包含A、B频繁使用A等条件)和C与A这两个耦合。在JDK的Map中Entry类的建立职责就分配给了持有它的Map。还有一个比较经典的例子就是Order建立SKU。设计
耦合是评价一个系统中各个元素(类、模块、子系统)之间依赖的程度,而良好的设计应该尽量下降这个程度。
如下是一些耦合关系的体现:orm
在以上的这些耦合条件中,出现得越多表明耦合程度越高。这些条件简单笼统的来讲就是A对B的“感知”。这种感知体如今对象属性、方法参数、方法返回值以及接口上面。高耦合的类过多地依赖其余类,这种设计将会致使:一个类的修改致使其余类产生较大影响,系统难以维护和理解。在重用一个高耦合的类时不得不重用它所依赖的其余类,系统重用性差。如何下降耦合的程度有如下一些方法:尽可能减小对其余类的引用,提升方法和属性的访问权限,尽可能使用组合/聚合原则来替代继承。
其实面向对象编程中的多态就是一种下降类型耦合的方法,若是没有多态的话,咱们的方法须要知道全部子类类型,而多态的话只须要知道父类便可。下降了类型耦合。htm
即功能性紧密相关的职责应该放在一个类里,并共同完成有限的功能。这点与SOLID原则当中的单一职责和接口隔离是一致的。对象
很直观的例子就是,若是类的功能都是高内聚并职责单一的,类的复杂性就下降了,复杂性下降致使维护的成本也就下降了。在传统的Dao设计模式当中,咱们应该尽可能拆分细粒度职责单一的Dao供Service进行调用。在Service当中,哪一类的数据操做调用哪个Dao就显而易见,而且单个Dao不会太过膨胀致使维护性变差。高内聚也表明了高隔离,高隔离就意味着,在修改某一个方法的时候,不至于影响到太多其余类。继承
把接收或者处理系统事件消息的职责分配给一个类。这个类能够表明:整个系统、设备或者子系统;系统事件发生时对应的用例场景,在相同的用例场景中使用相同的控制器来处理全部的系统事件。
一个控制器是负责接收或者处理事件的组件对象。MVC模式中的C就是控制器模式。而一个控制器应该处理一类事件。例如咱们项目中常常会有的UserController就承担添加用户,删除用户的事件。一个子系统须要定义多个控制器,分别对应不一样的事件处理。通常来讲,控制器应当把要完成的功能委托给Service或者其余业务处理对象,它只负责协调和控制业务流程,尽可能不要包含太多业务逻辑。
当相关选择或行为随类型(类)变化而变化时,用多态操做为行为变化的类型分配职责。
在面向对象的设计当中常常要根据对象的类型来进行对应的操做。假设咱们有一个画图Draw类,有多个图形类Rectangle、Circle、Square。若是要按照不一样图形类进行绘制的话,就须要在Draw类的方法中使用if-else的程序结构,依次判断类型进行绘制。若是新增一个图形类的话,就又须要对这段代码进行更改。这就违反了开闭原则。而采用多态的形式,将绘制的具体步骤交给图形类的子类实现。就不用使用if-else的程序结构,在新增图形类的时候也不须要修改Draw类。经过引入多态,子类对象能够覆盖父类对象的行为,更好地适应变化。策略模式、工厂方法模式就是关于多态比较好的例子。
将一组高内聚的职责分配给一个虚构的或处理方便的“行为”类,它并非问题域中的概念,而是虚构的事物,以达到支持高内聚、低耦合和复用。
OO设计中的领域模型是对领域内的概念或现实世界中的对象的模型化表示。建立领域模型的关键思想是减少软件人员的思惟与软件模式之间的表示差别。所以,在OO设计时,系统内的大多数类都是来源于现实世界中的真实类。然而,在给这些类分配职责时,有可能会遇到一些很难知足低耦合高内聚的设计原则。纯虚构模式对这一问题给出的方案是:给人为制造的类分配一组高内聚的职责,该类并不表明问题领域的概念,而表明虚构出来的事物。比较明显的一个例子就是适配器模式,经过虚构出适配器这么一个概念来解耦两个对象之间的耦合。
许多项目都须要对数据库进行操做,将系统中的一些对象进行持久化。信息专家模式给出的建议是将持久化的职责分配给具体的每个模型类。可是这种建议已经被证实是不符合高内聚低耦合原则的。因而,如今的作法每每会在项目中加入相似于DAO或者Repository这样的类。这些类在领域模型中是并不存在的。
分配职责给中间对象以协调组件或服务之间的操做,使得它们不直接耦合。中间对象就是在其余组件之间创建的中介。
“中介”简单来讲就是经过一个中间人来处理一件事。原本直接联系的两个对象能够经过另外一个中间对象进行交互,这样作便实现了隔离和解耦,一个对象的变更不会影响另外一个对象,仅会影响到中间对象。在设计模式当中的适配器模式,桥接模式都采用了一个中间对象来进行解耦。
找出预计有变化或不稳定的元素,为其建立稳定的“接口”而分配职责。
受保护变化模式简称PV,它是大多数编程和设计的基础,是模式的基本动机之一,它使系统可以适应和隔离变化。它与面向对象设计原则中的开闭原则相对应,即在不修改原有元素(类、模块、子系统或系统)的前提下扩展元素的功能。一个比较显而易见的例子就是策略模式,经过建立策略接口并定义其中的抽象方法来应对可能出现的新策略。未来有新的策略的时候不须要改变原代码,而是新建实现策略接口的类。