委托模式

委托模式 http://blog.sina.com.cn/s/blog_5f13e9910100g3ob.html http://www.iteye.com/topic/29541 委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得我们可以用聚合来替代继承,它还使我们可以模拟mixin。 “委托"在C#中是一个语言级特性,而在Java语言中没有直接的对应,但是我们可以通过动态代理来实现委托!代码如下: Java代码 收藏代码 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* @author Liusheng 实现"委托"模式,用户需要实现InvocationHandler接口; 参考: http://www.uml.org.cn/j2ee/200411036.htm */ public abstract class Delegator implements InvocationHandler { //RelegateTo针对每个对象都要生成一个实例,因而非Static的log,代价比较高。 //protected Log _log = LogFactory.getLog(this.getClass()); //private static Log _log = LogFactory.getLog(RelegateTo.class); //————— protected Object obj_orgin = null; //原始对象 protected Object obj_proxy = null; //代理对象 //————— public Delegator() { //空 } public Delegator(Object orgin){ this.createProxy(orgin); } //————— protected Object createProxy(Object orgin) { obj_orgin = orgin; obj_proxy = Proxy.newProxyInstance( orgin.getClass().getClassLoader(), //加载器 ...

2014-08-08 · 2 min · 267 words · -

JUDE,Astah

JUDE,Astah 随着UML的扩大,UML建模工具也越来越庞大。不过,许多功能并不是用户所寻求的。因此,Astah Professional (原名JUDE) 听取用户心声,根据用户需要打造,按照使用习惯设计,轻便简单,友好易用,用户可以轻松使用它来高速建模,极大的提高了效率。 Astah Professional 功能强大,支持 UML1.4中所有图和主要的图形,元模 (Meta Model) 及属性,全面满足您建模所需,还集成了思维导图,工程合并,协作开发等十余项特色功能,以及许多方便用户的贴心实用的功能。 Astah Professional 是100% 纯 Java 应用程序,可以跨平台在各种主流操作系统中使用。支持 OMG XMI标准格式,可以与其它建模工具交互模型。为方便用户书写 Office 文档,软件支持以 Microsoft EMF 增强图元拷贝粘贴至 Microsoft Office,也可以将模型信息导出到 Office Excel。软件提供了内容丰富的使用手册,全面查看 Astah Professional 所有的功能。

2012-11-09 · 1 min · 32 words · -

动态代理 Dynamic Proxy

动态代理 Dynamic Proxy 从JDK1.3开始,Java就引入了动态代理的概念。动态代理 (Dynamic Proxy) 可以帮助你减少代码行数,真正提高代码的可复用度。例如,你不必为所有的类的方法里面都写上相同的Log代码行,取而代之的是实用类的动态代理类。当然,这种便利是有条件的。本文简单介绍Java动态代理的原理,并实现一个被代理的Servlet创建,和调用的过程。 代理模式 (Proxy Pattern) 在JDK1.3以前,代理模式就已流行,所以得代理模式是生成一个和类相同接口的代理类,用户通过使用代理类来封装某个实现类。如图1,其目的是加强实现类的某个方法的功能,而不必改变原有的源代码。 <img src="http://p.blog.csdn.net/images/p_blog_csdn_net/tyrone1979/proxy1.JPG" alt="" /> 2.动态代理 (Dynamic Proxy) 随着Proxy的流行,Sun把它纳入到JDK1.3实现了Java的动态代理。动态代理和普通的代理模式的区别,就是动态代理中的代理类是由java.lang.reflect.Proxy类在运行期时根据接口定义,采用Java反射功能动态生成的。和java.lang.reflect.InvocationHandler结合,可以加强现有类的方法实现。如图2,图中的自定义Handler实现InvocationHandler接口,自定义Handler实例化时,将实现类传入自定义Handler对象。自定义Handler需要实现invoke方法,该方法可以使用Java反射调用实现类的实现的方法,同时当然可以实现其他功能,例如在调用实现类方法前后加入Log。而Proxy类根据Handler和需要代理的接口动态生成一个接口实现类的对象。当用户调用这个动态生成的实现类时,实际上是调用了自定义Handler的invoke方法。 <img src="http://p.blog.csdn.net/images/p_blog_csdn_net/tyrone1979/proxy2.JPG" alt="" width="683" height="284" /> 3.动态代理Servlet 虽然Web Application Server的产品很多,但Servlet的处理原理是相似的: 动态加载Servlet,调用Servlet的init方法 (只被调用一次) ,并保存到Servlet容器;Servlet使用时,调用Servlet的service方法。本文动态代理Servlet接口,使其init和service被调用时会在控制台打出方法调用前后信息。 首先实现2个Servlet,DefaultServlet和UserServlet ```java package org.colimas.servlet; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; public class DefaultServlet extends HttpServlet implements Servlet { public void init() throws ServletException { super.init(); System.out.println(DefaultServlet.class.getName()+":Running init"); } public String getServletInfo() { return DefaultServlet.class.getName(); } } package org.colimas.servlet; import java.io.IOException; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class UserServlet extends HttpServlet implements Servlet { private static final long serialVersionUID = -7016554795165038652L; public void init() throws ServletException { super.init(); System.out.println(UserServlet.class.getName()+":Running init"); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println(UserServlet.class.getName()+":Do UserSErvlet Get"); } public String getServletInfo() { return UserServlet.class.getName(); } } 然后实现InvocationHandler ...

2012-10-16 · 3 min · 547 words · -

UML 类的关系: 关联,聚合,组合的区别

UML 中关联,聚合,组合的区别 关联 Association 聚合 Aggregation Composition 类间关系 在类图中,除了需要描述单独的类的名称、属性和操作外,我们还需要描述类之间的联系,因为没有类是单独存在的,它们通常需要和别的类协作,创造比单独工作更大的语义。在 UML 类图中,关系用类框之间的连线来表示,连线上和连线端头处的不同修饰符表示不同的关系。类之间的关系有继承 (泛化) 、关联、聚合和组合。 关联 (Association) 关联指的是模型元素之间的一种语义联系,是类之间的一种很弱的联系。关联可以有方向,可以是单向关联,也可以是双向关联。可以给关联加上关联名来描述关联的作用。关联两端的类也可以以某种角色参与关联,角色可以具有多重性,表示可以有多少个对象参与关联。可以通过关联类进一步描述关联的属性、操作以及其他信息。关联类通过一条虚线与关联连接。对于关联可以加上一些约束,以加强关联的含义。 class A: pass class B: def func_0(a:A) # 一个类作为另一个类方法的参数 聚合 (aggregation) 指的是整体与部分的关系。通常在定义一个整体类后,再去分析这个整体类的组成结构。从而找出一些组成类,该整体类和组成类之间就形成了聚合关系。例如一个航母编队包括海空母舰、驱护舰艇、舰载飞机及核动力攻击潜艇等。需求描述中"包含"、“组成”、“分为…部分"等词常意味着聚合关系。 在聚合中,所包含的类并不强烈依赖于容器的生命周期。在同一示例中,即使图书馆解散,书籍仍将保留。 聚合使用一个带有 空心菱形 的箭头表示,菱形指向"整体"类。 class School class Student Student --o School 组合 (composition) 也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在。部分对象与整体对象之间具有共生死的关系。 组合使用一个带有 实心菱形 的箭头表示,菱形指向"整体"类。 class Person class Heart Heart --* Person 聚合和组合的区别在于: 聚合关系是"has-a"关系,组合关系是"contains-a"关系;聚合关系表示整体与部分的关系比较弱,而组合比较强;聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。 我们用浅显的例子来说明聚合和组合的区别。"国破家亡",国灭了,家自然也没有了,"国"和"家"显然也是组合关系。而相反的,计算机和它的外设之间就是聚合关系,因为它们之间的关系相对松散,计算机没了,外设还可以独立存在,还可以接在别的计算机上。在聚合关系中,部分可以独立于聚合而存在,部分的所有权也可以由几个聚合来共享,比如打印机就可以在办公室内被广大同事共用。 在C++语言中,从实现的角度讲,聚合可以表示为: class A {...} class B { A* a; .....} 即类B包含类A的指针; 而组合可表示为: class A{...} class B{ A a; ...} 即类B包含类A的对象。 准确的UML类图中用空心和实心菱形对聚合和组合进行了区分。 关联和聚合的区别主要在语义上,关联的两个对象之间一般是平等的,例如你是我的朋友,聚合则一般不是平等的,例如一个公司包含了很多员工,其实现上是差不多的。聚合和组合的区别则在语义和实现上都有差别,组合的两个对象之间其生命期有很大的关联,被组合的对象是在组合对象创建的同时或者创建之后创建,在组合对象销毁之前销毁。一般来说被组合对象不能脱离组合对象独立存在,而且也只能属于一个组合对象,例如一个文档的版本,必须依赖于文档的存在,也只能属于一个文档。聚合则不一样,被聚合的对象可以属于多个聚合对象,例如一个员工可能可以属于多个公司。 我想举个通俗的例子。 你和你的心脏之间是composition关系 (心脏只属于你自己) 你和你买的书之间是aggregation关系 (书可能是别人的) 你和你的朋友之间是assoc 继承 (Extension) 指的是一个类 (称为子类) 继承另外的一个类 (称为基类) 的功能,并增加它自己的新功能的能力,继承是类与类之间最常见的关系。 ...

2012-10-15 · 5 min · 970 words · -

抽象工厂模式解析例子

抽象工厂模式解析例子 抽象工厂模式中的有以下的四种角色: 抽象工厂 (Abstract Factory) 角色: 担任这个角色的是工厂方法模式的核心,它是与应用系统业务逻辑无关的。 具体工厂 (Concrete Factory) 角色: 这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的业务逻辑紧密相关的。 抽象产品 (Abstract Product) 角色: 担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。 具体产品 (Concrete Product) 角色: 这个角色用以代表具体的产品。 抽象工厂模式就相当于创建实例对象的new,由于经常要根据类生成实例对象,抽象工厂模式也是用来创建实例对象的,所以在需要新的事例对象时便可以考虑是否使用工厂模式。虽然这样做可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。 举例来说: 生产餐具和相应食物的工厂,有两个车间,其中一个车间用以生产餐具,一个车间用以生产相应的食物。 当消费者消费时,只需要向相应的具体工厂请求具体餐具和具体食物便可以使用餐具消费食物。 每个具体工厂生产出来的具体产品根据不同工厂的不同各不相同,但是客户使用产品的方法是一致的。比如客户在得到餐具和食物之后,两者的搭配是正确的 (使用汤匙喝牛奶,使用刀子切面包) 。 在本例子中有3个具体工厂AKetchen, BKetchen, BKetchen,分别生产牛奶和汤匙、面包和刀、肉和叉子。牛奶、面包和肉都实现了食物接口。汤匙、刀和叉子都实现了餐具接口。 抽象工厂的接口定义如下所示; public interface KetchenFactory{ public Food getFood(); public TableWare getTableWare(); } //抽象餐具的接口定义如下所示: public interface TableWare{ public String getTool(); } //抽象食物的接口定义如下所示: public interface Food{ public String getEatable(); } //而具体的实现也非常简单,以AKetchen为例子 //具体工厂AKetchen的定义如下所示; public class AKetchen implements KetchenFactory{ public Food getFood(){ return new Milk(); } public TableWare getTableWare(){ return new Spoon(); } } //具体餐具(spoon)的定义如下所示: public class Spoon implements TableWare{ public String getTool() { return "spoon"; } } //具体食物(milk)的定义如下所示: public class Milk implements Food{ public String getEatable(){ return "milk"; } } //客户端的定义如下: public class Client{ public void eat(KetchenFactory k){ System.out.println("A person eat "+k.getFood().getEatable() +" with "+k.getTableWare().getTool()+"!"); } public static void main(String[] args){ Client client= new Client(); KetchenFactory kf = new AKetchen(); client.eat(kf); kf=new BKetchen(); client.eat(kf); kf= new CKetchen(); client.eat(kf); } } 小结: 抽象工厂模式特别适合于这样的一种产品结构: 产品分为几个系列,在每个系列中,产品的布局都是要同的,在一个系列中某个位置的产品,在另一个系列中一定有一个对应的产品。这样的产品结构是存在的,这几个系列中同一位置的产品可能是互斥的,它们是针对不同客户的解决方案,每个客户都只择其一。 ...

2012-10-09 · 1 min · 159 words · -

GOF 23 种设计模式, Design pattern

GOF 23 种设计模式, Design pattern 在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。 四位作者合称 GOF(四人帮,全拼 Gang of Four)。 单例 (Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式 [[Singleton#单例模式 Singleton]] 原型 (Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。[[prototype模式#原型模式 Prototype]] 工厂方法 (Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。 抽象工厂 (AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。 建造者 (Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。[[创建者模式-builder#创建者模式 建造者模式 Builder]] 代理 (Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。[[proxy-pattern#代理模式 proxy pattern]] 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。[[adapter]] 桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。 装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。 享元 (Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。 组合 (Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。 模板方法 (TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。[[Template-Method#设计模式 – 模板方法 Template Method]] 策略 (Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。[[设计模式-策略strategy#设计模式 – 策略 Strategy]] 命令模式 (Command):将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。 职责链 (Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。 状态 (State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。 观察者 (Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。 中介者 (Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。 迭代器 (Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。 访问者 (Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。 备忘录 (Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。 解释器 (Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。 分类 创建模式, Creational Patterns Simple Factory 简单工厂模式 https://blog.wiloon.com/?p=1399 Factory Method 工厂方法 Abstract Factory 抽象工厂模式 Prototype, 原型 Builder, 建造者 Singleton, 单例 结构模式, Structural Patterns Facade, 外观 Proxy, 代理 Adapter, 适配器 Composite, 组合 Decorator, 装饰器 https://blog.wiloon.com/?p=847 Bridge, 桥接 Flyweight, 享元 行为模式, Behavioral Patterns Template Method, 模板方法 Memento, 备忘录 Observer - 观察者 https://wiloon.com/observer Chain Of Responsibility, 责任链 Command, 命令模式 (别名: 动作模式(Action)或事务模式(Transaction)) State, 状态 Strategy, 策略 Mediator, 中介者 Interpreter, 解释器 Visitor, 访问者 Iterator, 迭代器 GoF: (Gang of Four,GOF设计模式) - 四人组 Design Patterns: Elements of Reusable Object-Oriented Software (即后述《设计模式》一书) ,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著 (Addison-Wesley,1995) 。这几位作者常被称为"四人组 (Gang of Four) “,而这本书也就被称为"四人组 (或 GoF) “书。 ...

2011-10-29 · 2 min · 379 words · -

可扩展性, scalability

可扩展性, scalability 可扩展的本质是什么? 可扩展的意思是在面对变化时,用最少的代价去实现,平时我们听得最多的是面向抽象(接口)编程,如果只是把这里的抽象理解成接口,那么就有些狭隘了,抽象是通式通法,而接口只是其中一个,所以在谈可扩展实现之前一定要讲清楚可扩展的本质是什么,连本质都不知道,怎么提出系统性解决方案。 1.1 扩展的本质 扩展的本质就是占位符,明确告诉你这里被占了,具体谁占了不清楚。那么问题来了:占位符到底是什么?它是怎么表达的?又要如何实现的?如果可以把这三个问题理清楚,就可以想到很多可扩展性方案,而不再是单一的面向接口编程。 占位符到底是什么:占位符仅仅是一个标识,标志这里会有变化,一句话可以概括:凡是可以表达变化的就是占位符,然而具体的变化实现又没有给出,真正体现了做什么和怎么做的分离。 占位符怎么表达:要回答这个标识是用什么来表达,变量、接口、配置项…这些都可以表达占位符,变量能被赋值同一类型的数据;接口可以有不同的实现;配置项也可以被赋予不同的值…所以,实现可扩展的思路一下就打开了。 如何实现:再往深层次思考,实现一个接口,如何在执行时动态找到实现类?如果把这个问题想清楚,在实际中实现可扩展又会有一套系统性解决方案。整个过程就两点:识别和执行,识别的意思就是要找到对应目标,接下来就是执行。 综上,到这里可能已经有自己应对可扩展的方法,上面已经给了从不同角度看可扩展性的示例,接下来就是系统化提出应对可扩展的方法。 结论一:扩展的本质就是占位符,凡是可以表达变化的就是占位符。 1.2 应对可扩展的方法 先给出应对可扩展的方法:规范、识别、注册、使用,这 4 点都是从上面可推导出来的,下面一一进行详细说明。 规范:规范是从占位符推导出来的,既然是标志有变化,一定要遵循一定的规范表达,否则别人是不知道的,如接口,就是很直接地表达这里是有变化的,具体的实现还不知道;变量天然地表达这里是变化的数据。 识别:有了规范定义之后,接下来就是识别,之前为什么可扩展一直对我们来讲很虚,那是因为规范和识别都是系统帮我们做的,我们只是知道而没有真正实践。规范是定义,识别是找出有哪些实现了规范。 注册:识别出来之后,就要把信息存储起来,可以存储在本地,也可以存储在远程,如果存储在远程就是一个注册的过程,这里的注册就是存储的意思。简单理解就是识别出来之后要集中管理。 使用:使用就很简单,找到具体实现并执行逻辑处理。 上面四个单词看起来简单,除了使用是终极目标外,其它三个都是抽象的表达,比如规范如何定义、怎么识别、如何注册?通过上面的表述可以看到具体要怎么实践,这里再总结下: 规范如何去定义:凡是可以表达变化的就能用它来定义,常见的有配置项、变量、接口、注解等; 怎么去识别:这个要具体去看如何定义规范,如配置项的变化有一个监听变化;注解是要扫描类来识别 annotation; 如何去注册:如果系统的交互只是一个,那么存储在本地就行,如果系统的交互是多个,那么要注册到一个注册中心上去。 结论二:应对可扩展的方法:规范、识别、注册、使用。 https://www.infoq.cn/article/1w2mjzzx-0dm9j9vysam

2011-09-08 · 1 min · 28 words · -

命令模式, Command pattern

命令模式, Command pattern 命令模式, Command pattern , 行动(Action)模式或者交易(Transaction)模式 定义 命令模式属于对象的行为模式。命令模式又称为行动(Action)模式或者交易(Transaction)模式。 命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。 命令模式的结构 命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分隔开,委派给不同的对象。 每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方接收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收、以及操作是否被执行、何时被执行、怎么被执行的。 命令允许请求的一方和接收请求的一方能够独立演化,从而具有如下的优点: 命令模式使新的命令很容易被加入到系统里。 允许接受请求的一方决定是否要否决请求。 能较容易的设计一个命令队列。 可以容易的实现对请求的撤销和恢复。 在需要的情况下,可以较容易的将命令记入日志。 下面是一个示意性的系统,说明命令模式的结构: 示意性命令模式结构 命令模式涉及到五个角色,他们分别是: 客户端角色(Client):创建一个具体命令ConcreteCommand对象并确定其接收者。 命令角色(Command): 声明一个给所有具体命令类的抽象接口。 具体命令角色(ConcreteCommand):定义一个接收者和行为之间的弱耦合;实现execute()方法,负责调用接收者的相应操作。execute()方法通常叫做执行方法。 请求者角色(Invoker):负责调用命令对象执行请求,相关的方法叫做行动方法。 接收者角色(Receiver):负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。 命令模式的优点 更松散的耦合 命令模式是的发起命令的对象——客户端,和具体实现命令的对象——接收者对象完全解耦,也就是说发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。 更动态的控制 命令模式把请求封装起来,可以动态的对它进行参数化、队列化和日志化等操作,从而使得系统更灵活。 很自然的复合命令 命令模式中的命令对象能够很容易的组合成复合命令,也就是宏命令,从而是系统操作更简单,功能更强大。 更好的拓展性 由于发起命令的对象和具体的实现完全解耦,因此拓展新的命令就很容易,只需要实现新的命令对象,然后在装配的时候,把具体的实现对象设置到命令对象中,然后就可以使用这个命令对象,已有的实现完全不用变化。 作者:步积 链接:https://www.jianshu.com/p/5901e76a6348 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html

2011-08-29 · 1 min · 43 words · -

无状态服务, stateless service

无状态服务, stateless service https://blog.csdn.net/xiangxizhishi/article/details/79434749 一、定义 无状态服务(stateless service)对单次请求的处理,不依赖其他请求,也就是说,处理一次请求所需的全部信息,要么都包含在这个请求里,要么可以从外部获取到(比如说数据库),服务器本身不存储任何信息 有状态服务(stateful service)则相反,它会在自身保存一些数据,先后的请求是有关联的 二、优劣 有状态服务常常用于实现事务(并不是唯一办法,下文有另外的方案)。举一个常见的例子,在商城里购买一件商品。需要经过放入购物车、确认订单、付款等多个步骤。由于HTTP协议本身是无状态的,所以为了实现有状态服务,就需要通过一些额外的方案。比如最常见的session,将用户挑选的商品(购物车),保存到session中,当付款的时候,再从购物车里取出商品信息 有状态服务可以很容易地实现事务,所以也是有价值的。但是经常听到一种说法,即server要设计为无状态的,这主要是从可伸缩性来考虑的。如果server是无状态的,那么对于客户端来说,就可以将请求发送到任意一台server上,然后就可以通过负载均衡等手段,实现水平扩展。如果server是有状态的,那么就无法很容易地实现了,因为客户端需要始终把请求发到同一台server才行,所谓“session迁移”等方案,也就是为了解决这个问题 三、session和cookie 基于session和cookie都可以实现事务,可以认为,session是有状态的,而cookie是无状态的 四、无状态实现事务的方法 并不是一定要用有状态服务才能实现事务,本文提供另外的几种方案作为参考 举一个多次提交的场景作为例子:用户需要提交很多数据,分为2个页面提交 这里就涉及到2次http请求,第一次提交字段1、2、3,第二次提交字段4、5、6 用session很容易实现这个需求,server只需要将第一次提交的数据,保存在session里,然后返回第2个表单作为相应;然后取出第一次提交的数据,和第二次提交的数据汇聚以后,一起存入数据库即可 不用session同样也可以实现,server接收到第一次请求以后,将数据作为隐藏元素,放在第2个表单里返回;这样用户第2次提交的时候,就隐含地再次提交了第一次的数据;server将所有数据存入数据库 用HTML5,则还可以进一步优化,client可以将第一次提交的数据,保存在sessionStorage里 用cookie也是类似的道理,同样可以实现,但是不太好 总的来说,3种替代方案(隐藏表单元素、sessionStorage、cookie)都避免了在server端暂存数据,从而实现了stateless service。本质上,这3种方案的请求里,都包含了所有必须的数据,符合本文一开始的定义 五、将有状态服务转换成无状态服务 根据本文一开始的定义,除了将所有信息都放在请求里之外,还有另外一种方法可以实现无状态服务,即将信息放在一个单独可共享的地方,独立于server存在 比如,同样还是采取session的方式,在服务端保存数据,减少每次client请求传输的数据量(节省流量);但是将session集中存放,比如放在单独的session层里。这种情况下,server同样是无状态的,可以做水平扩展 六、无状态类 引申一下,JAVA里有一种类的设计,可以称为无状态类。这种类的特征是只有方法没有字段,在三层架构(展现层、逻辑层、持久层)里,逻辑层经常可以看到这种类 我觉得无状态类和stateless server在思想上是一样的,这个类本身是没有状态的,所以当外部要调用它的方法时,需要在方法参数中传来所需的所有信息,不依赖该类自身的状态(字段值),在并发环境下,可以避免多线程带来的副作用 七、总结 有状态服务可以比较容易地实现事务,在不需要考虑水平扩展时,是比较好的选择 无状态服务的优势在于可以很方便地水平伸缩,但是在实现事务时,需要做一些额外的动作 可以通过剥离session等方法,将一个有状态服务,转换成无状态服务 关于这个话题,下面这个链接也不错: http://stackoverflow.com/questions/4495950/how-do-stateless-servers-work

2006-01-02 · 1 min · 37 words · -

实体和值对象, entity, value object

实体和值对象, entity, value object 实体和值对象 实体和值对象放在一起讲容易区分,概括而言,实体不仅需要知道它是什么?而且还需要知道它是哪个?而值对象只需要知道它是什么?先看定义: 实体 许多对象不是由它们的属性来定义,而是通过一系列的连续性(continuity)和标识(identity)来从根本上定义的。只要一个对象在生命周期中能够保持连续性,并且独立于它的属性(即使这些属性对系统用户非常重要),那它就是一个实体。 值对象:当你只关心某个对象的属性时,该对象便可作为一个值对象。为其添加有意义的属性,并赋予它相应的行为。我们需要将值对象看成不变对象,不要给它任何身份标识,还应该尽量避免像实体对象一样的复杂性。 对于实体Entity,实体核心是用唯一的标识符来定义,而不是通过属性来定义。即即使属性完全相同也可能是两个不同的对象。同时实体本身有状态的,实体又演进的生命周期,实体本身会体现出相关的业务行为,业务行为会实体属性或状态造成影响和改变。 如果从值对象本身无状态,不可变,并且不分配具体的标识层面来看。那么值对象可以仅仅理解为实际的Entity对象的一个属性结合而已。该值对象附属在一个实际的实体对象上面。值对象本身不存在一个独立的生命周期,也一般不会产生独立的行为。 初看还是很难理解,举几个例子: 案例分析 营业厅会卖手机以及很多手机配件,在客户业务规则中,往往每一部手机都要单独管理,通过手机的SN号来识别。而手机配件是一种数量类型的实物,只关心其数量的变化,并不关心到每一个具体的手机配件。这种场景就是典型的实体和对象的案例。 地址是实体还是值对象。在电力公司服务软件中,一个地址对应于公司线路和服务的目的地。如果多个住所都申请了电力服务,那么这个公司需要知道这一点,因此地址是实体。我们也可以用另一种方法,在模型中将“住所”关联到运营服务,其中“住所”是一个包含地址属性的实体。此时,地址就是一个值对象。 体育场座位例子。当我们发放的门票上有座位号的时候,座位需要作为独立的实体,座位号是唯一的标识。而当先到先座模式下,我们只关心剩余座位数,那么座位号并不是唯一标识,这时候座位就可以作为一个值对象。这跟我们的业务需求有关。 消息场景中,发件人、收件人是实体?还是值对象?这个在 三个问题思考实体和值对象一文中有讨论。 值对象的常见例子包括数字,比如100和293.51;或者文本字符串,比如"hello world";或者日期时间;还有更加详细的对象,此如某人的全名,其中包含姓改、名字和头衔;再比如货币、颜色、电话号码和邮寄地址等。当然还有更加复杂的值对象。这种对象无状态,本身不产生行为,不存在生命周期演进。 值对象的目的和使用 实体对象相对容易理解,我们常见的类的都可以看成是实体对象。值对象在DDD中相对而言是难以理解并且容易误用的。 为什么需要使用值对象,书中给了一个解释: 使用不变的值对象使得我们做更少的职责假设 个人理解这个还是基于BC的封闭性而言的,使用值对象在不同的BC中进行数据交换,可以避免不同BC对实体对象的状态变更而引发的数据依赖关系,实现最小化的集成。另外可以从目前流行的Stateless Service角度考虑值对象的价值。 开发者因为习惯趋向于将关注点放在数据而不是领域上。在软件开发中,数据库依然占据着主导地位。我们首先考虑的是数据的属性(对应数据库的列)和关联关系(外键关联),而不是富有行为的领域概念。这样做的结果是将数据模型直接反映在对象模型上,导致产生贫血型的领域模型的实体。虽然在实体模型中加入getter和setter并不是什么大错,但这却不是DDD的做法。 值类型用于度量和描述事物,DDD 中建议应尽量使用值对象来建模而不是实体对象,因为值对象非常容易地对值对象进行创建、测试、使用、优化和维护。 关于值对象,它拥有以下一些特征: 它度量或者描述了领城中的一件东西。 它可以作为不变量。 它将不同的相关的属性组合成一个概念整体(Conceptual Whole) 当度量和描述改变时,可以用另一个值对象予以替换。 它可以和其他值对象进行相等性比较。 它不会对协作对象造成副作用 一个对象的方法可以设计成一个无副作用函数(Side-Effect-Free Function) 。这里的函数表示对某个对象的操作,它只用于产生输出, 而不会修改对象的状态。由于在函数执行的过程中没有状态改变,这样的函数操作也称为无副作用函数。对于不变的值对象而言,所有的方法都必须是无副作用函数,因为它们不能破坏值对象的不变性。 最小化集成 在所有的DDD项目中,通常存在多个限界上下文,这意味着我们需要找到合适的方法对这些上下文进行集成。当模型概念从上游上下文流入下游上下文中时, 尽量使用值对象来表示这些概念。这样的好处是可以达到最小化集成,即可以最小化下游模型中用于管理职责的属性数目。使用不变的值对象使得我们做更少的职责假设。 https://www.cnblogs.com/ttaylor/p/15927009.html DDD 领域驱动设计-三个问题思考实体和值对象 消息场景:用户 A 发送一个消息给用户 B,用户 B 回复一个消息给用户 A。。。 现有设计:消息设计为实体并为聚合根,发件人、收件人设计为值对象。 三个问题: 实体最重要的特性是什么? Message 实体是怎么得来的? 发件人、收件人为什么不是实体? 实体最重要的特性是什么? 《领域驱动设计》5.2 实体: 摘录一段:许多对象不是由它们的属性来定义,而是通过一系列的连续性(continuity)和标识(identity)来从根本上定义的。 归纳: 标识(identity) 连续性(continuity) 标识在实体中的另一种体现就是唯一和不可变,其概念在很多资料中有说明,这也是实体最重要的特性。 我有一个双胞胎哥哥,我们俩出生的时候,长得一模一样,以至于我们的爸妈都分不清,不得已他们在我们脖子上系个项链来标记:谁是老大?谁是老二?其实这个“标记”就可以看作是实体的标识,只不过是用项链来标识的,就像我们在项目中使用 GUID 方式一样,目的就是用来体现标识,但不管用什么方式表示,这个标识必须在这个特定环境下唯一,也就是说,我和我双胞胎哥哥的项链不能完全一样,要不然我爸妈就不能区分我们俩了。 ...

2 min · 238 words · -