DDD

DDD 领域驱动设计 (Domain-Driven Design,简称 DDD) Domain Layer 领域层 - 业务实体, 值对象, 领域服务 Infrastructure Layer 基础设施层 - 数据访问, 外部服务调用等技术实现 Application Layer 应用层 - 协调领域对象来执行应用用例 Interface Layer 接口层 - API 控制器, 视图 值对象 (Value Objects) 实体对象 (Entity) Repository 模式 - 抽象的数据访问层 聚合根 Factory 模式 Domain Service 值对象 (Value Objects) 代表领域中没有身份标识但有重要意义的概念 不可变性 (Immutability), 一旦创建,不能修改, 只读属性 基于值的相等性 (Value-based Equality), 比较的是值,不是对象引用 无身份标识 (No Identity), 两个值相同的对象被认为是相等的 可哈希性 (Hashable) 生命周期 短暂,可替换 封装业务逻辑: 比如某些固定规则的字符串组合 值对象的使用场景: 复合标识符 实体对象 (Entity) 有唯一身份ID ...

2026-01-26 · 3 min · 576 words · -

plantuml, puml

plantuml, puml UML 序列图, Sequence Diagram 用例图, Use Case Diagram 类图, Class Diagram 对象图, Object Diagram 活动图, Activity Diagram 组件图, Component Diagram 部署图, Deployment Diagram 状态图, State Diagram 时序图, Timing Diagram 非 UML 图 架构图, Archimate diagram UML 图 时序图, Sequence Diagram @startuml Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response Alice -> Bob: Another authentication Request Alice <-- Bob: Another authentication Response Alice ->> Bob: async msg @enduml 类图, Class Diagram @startuml skinparam classFontColor red class Foo note left: parent class Bar Bar : String field0 Bar : String method0() Foo<|--Bar note left: child abstract class Abstract0 Foo--|>Abstract0 interface Interface0 ' 注意, 接口名和冒号之间必须用空格分隔 Interface0 : void method0() class Class0{ - private_field_0 } @enduml @startuml skinparam class { BackgroundColor Lightblue ArrowColor #0ACF97 BorderColor #d5d5d5 } skinparam stereotypeCBackgroundColor YellowGreen Class101 <|.. Class102 @enduml 活动图, Activity Diagram @startuml !theme plain start if (foo?) then (yes) :process0; else (no) :process1; endif stop @enduml 组件图, Component Diagram 别名后面可以标注颜色 修改线和箭头的颜色 文字颜色 语法 # 把组件显示成普通矩形 skinparam componentStyle rectangle # 组件间横向距离 skinparam nodesep 10 # 组件间纵向距离 skinparam ranksep 10 @startuml skinparam componentStyle rectangle skinparam nodesep 10 skinparam ranksep 10 skinparam ParticipantFontColor #A9DCDF ' comments line starts by single quote, 注释 [First component] [Another component] as Comp2 component Comp3 component [Last\ncomponent] as Comp4 [component0] as c0 #ff0000 [<color:#ff0000>component1</color>] as c1 [component2] as c2 [component3] as c3 [component4] as c4 c0 -- c1 c0-[#00ff00]-c2 c1--c3 c0--c3 c2--c4 note left of c0 note0 end note @enduml 部署图, Deployment Diagram @startuml circle 1 circle 2 circle 3 agent 4 1 -- 2 1 -- 3 1 -- 4 queue 5 4 -right- 5 5 -right-2 @enduml 状态图, State Diagram @startuml [*] --> State1 State1 --> [*] State1 : this is a string State1 : this is another string State1 -> State2 State2 --> [*] @enduml 安装 graphviz sudo apt-get install -y graphviz https://graphviz.org/download/ ...

2024-03-19 · 3 min · 620 words · -

Reactor, Dispatcher 模式

Reactor / Dispatcher 模式 了解 Reactor 模式,就要先从事件驱动的开发方式说起。 我们知道,服务器开发,CPU 的处理速度远高于 IO 速度,为了避免 CPU 因为 IO 而阻塞,好一点的方法是多进程或线程处理,但这会带来一些进程切换的开销。 这时先驱者找到了事件驱动,或者叫回调的方法。这种方式就是,应用向一个中间人注册一个回调 (Event handler),当 IO 就绪后,这个中间人产生一个事件,并通知此 handler 进行处理。这种回调的方式,也实现了"好莱坞原则" - “Don’t call us, we’ll call you.” 那在 IO 就绪这个事件后,谁来充当这个中间人?Reactor 模式的答案是: 有一个不断等待和循环的单独进程 (线程) 来做这件事,它接受所有 handler 的注册,并负责向操作系统查询 IO 是否就绪,在就绪后用指定的 handler 进行处理,这个角色的名称就叫做 Reactor。 事件驱动, 回调函数, reactor, 响应式编程 事件驱动是概念,回调函数是实现方式。不用回调函数,也可以实现事件驱动。例如:把事件消息发送到队列,另外一个进程取队列处理即可 (没有回调函数)。事件驱动的本质特征:中心轮询机制。event loop的loop是轮询。轮询的目的是什么?感知!对象发生变化,如何感知这种变化?不断的循环查询,loop探测!系统n个对象,每个对象一个for循环 探测彼此的变化?nonono……建立一个轮询中心,这个轮询中心去轮询每个对象,这就是事件驱动。发生了变化,通知感兴趣的对象,怎么处理?就是定义一个回调函数。事件驱动,属于“感知层”的概念;轮询中心,往往就是操作系统本身;对于浏览器而言,就是浏览器本身。也就是系统是轮询中心,你定义 函数,系统调用你定义的函数。对比:系统定义api,你调用api。谁定义函数,谁调用,角色颠倒了!api:系统定义的函数,你去调用; 事件驱动:你定义的回调函数,被系统调用。还是没有懂?事件驱动,就是“哨兵模式”!哨兵轮询环境信息,你就安心睡大觉好了,不用每个人都轮询环境。发生了事件,哨兵 (操作系统/浏览器/轮询中心)负责通知你!怎么处理这个消息,是你的责任! 作者:fdego 链接:https://www.zhihu.com/question/30396023/answer/447966119 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 事件驱动, reactor The reactor design pattern is an event handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. https://en.wikipedia.org/wiki/Reactor_pattern ...

2021-07-11 · 3 min · 621 words · -

架构, 架构师, architecture

架构, 架构师, architecture 架构师: architect 架构: architecture 软件架构 软件架构 (software architecture) 就是软件的基本结构。 分层架构 分层架构 (layered architecture) 是最常见的软件架构,也是事实上的标准架构。如果你不知道要用什么架构,那就用它。 这种架构将软件分成若干个水平层,每一层都有清晰的角色和分工,不需要知道其他层的细节。层与层之间通过接口通信。 虽然没有明确约定,软件一定要分成多少层,但是四层的结构最常见。 表现层 (presentation) : 用户界面,负责视觉和用户互动 业务层 (business) : 实现业务逻辑 持久层 (persistence) : 提供数据,SQL 语句就放在这一层 数据库 (database) : 保存数据 有的软件在逻辑层和持久层之间,加了一个服务层 (service) ,提供不同业务逻辑需要的一些通用接口。 用户的请求将依次通过这四层的处理,不能跳过其中任何一层。 事件驱动架构 事件 (event) 是状态发生变化时,软件发出的通知。 事件驱动架构 (event-driven architecture) 就是通过事件进行通信的软件架构。它分成四个部分。 事件队列 (event queue) : 接收事件的入口 分发器 (event mediator) : 将不同的事件分发到不同的业务逻辑单元 事件通道 (event channel) : 分发器与处理器之间的联系渠道 事件处理器 (event processor) : 实现业务逻辑,处理完成后会发出事件,触发下一步操作 微核架构 微核架构 (microkernel architecture) 又称为"插件架构" (plug-in architecture) ,指的是软件的内核相对较小,主要功能和业务逻辑都通过插件实现。 ...

2019-10-11 · 2 min · 326 words · -

响应式编程, Reactive Programming, 反应式编程

响应式编程, Reactive Programming, 反应式编程 Reactive Programming 作为观察者模式 (Observer) 的延伸,不同于传统的命令编程方式 ( Imperative programming) 同步拉取数据的方式,如迭代器模式 (Iterator)。而是采用数据发布者同步或异步地推送到数据流 (Data Streams)的方案。当该数据流 (Data Steams)订阅者监听到传播变化时,立即作出响应动作。在实现层面上,Reactive Programming 可结合函数式编程简化面向对象语言语法的臃肿性,屏蔽并发实现的复杂细节,提供数据流的有序操作,从而达到提升代码的可读性,以及减少 Bug 出现的目的。同时,Reactive Programming 结合背压 (Backpressure) 的技术解决发布端生成数据的速率高于订阅端消费的问题。 https://developer.aliyun.com/article/617709 响应式编程为 Java 的企业版应用提供了更高的性能,并降低了内存消耗,主要是通过减少进程的上下文切换来实现的。因为类似的上下文切换对 CPU 和内存的消耗是极大,所以要尽可能的减少这样的切换操作。不过,响应式编程带来的这种性能上的提高,代价是降低了软件的维护性 java 使用一对一的线程模型,一个java线程对应一个内核线程, 高并发情况下 线程上下文切换成为了瓶颈. 而这正是响应式编程的用武之地,它与目前的 Java 线程模型完全相反。目前的线程模型是保证所有的事情都在当前线程执行,但是在响应式编程中,异步是一个准则。一个程序执行过程被认定为一系列异步执行的事件,每个事件都被 Publisher 创建,你不需要关心 Publisher 在哪个线程中创建。在响应式程序里面,程序代码包含了监听和执行异步事件的功能,而且会在必要时提供新的事件。 这个方式在某些场景下很有效果,比如说在程序里面访问外部数据库。传统的企业级 Java 程序里面,系统会发送一段 SQL 语句到数据库上面,阻塞住程序,直到数据库返回查询结果。但是在响应式编程里面,程序会跳过等待结果的过程,正常向下执行代码。当你发送一个 SQL 请求到数据库的时候,会用一个 Pushlisher 来替代阻塞的过程,调用者可以注册这个 Pushlisher,这样的话,在之后数据库返回结果的时候,就会通知 Publisher,然后 Publisher 会通知调用者。 响应式编程的好处就是执行的代码和执行的线程是分开的。因此在操作系统的层面上,上下文切换的代价比较低。 响应式编程也有一些比较严重的问题,写入的代码和执行的代码分离开来,导致阅读和编写代码的难度增加,对于这种异步的代码,编写单元测试和调试代码都很困难。 类似于 C Sharp、JavaScript、Kotlin 等这一类的编程语言在这个领域已经走在了前面,他们在编程语言中集成了这部分功能,可以帮助你执行一小段异步代码,并在返回的时候阻塞,直到执行结束。在 C Sharp 和 JavaScript 中,可以使用 Async 和 Await 关键字,在 Go 和 Kotlin 中,同样包括了协程的概念来提供类似的功能。 ...

2019-05-10 · 1 min · 119 words · -

舱壁模式

舱壁模式 什么是舱壁模式 舱壁模式 (Bulkhead) 隔离了每个工作负载或服务的关键资源,如连接池、内存和CPU。 使用舱壁避免了单个工作负载 (或服务) 消耗掉所有资源,从而导致其他服务出现故障的场景。 这种模式主要是通过防止由一个服务引起的级联故障来增加系统的弹性。 工业中使用舱壁将船舶划分为几个部分,以便在船体破坏的情况下,可以将船舶各个部件密封起来。舱壁的概念在软件开发中可以被应用在隔离资源上。通过应用舱壁模式,我们可以保护有限的资源不被耗尽。例如,对于一个有连接数限制的数据库实例来说,如果我们有两种连接它的操作,我们采用可以采用两个连接池的方式进行连接,来代替仅采用一个共享连接池的方式。由于这种客户端与资源进行了隔离,超时或过度使用池的操作页不会使其他操作失败。泰坦尼克号沉没的主要原因之一是其舱壁设计失败,水可以通过上面的甲板倒在舱壁的顶部,导致整个船体淹没。 作者: AskHarries 链接: https://juejin.im/post/5b32d3e36fb9a00e952ce899 来源: 掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2019-04-28 · 1 min · 17 words · -

设计模式, Design Pattern, Front Controller Pattern

设计模式, Design Pattern, Front Controller Pattern http://www.cnblogs.com/TonyYPZhang/p/5516192.html Front Controller Pattern, 即前端控制器模式,用于集中化用户请求,使得所有请求都经过同一个前端控制器处理,处理内容有身份验证、权限验证、记录和追踪请求等,处理后再交由分发器把请求分发到对于的处理者。 前端控制器模式主要涉及下面三个角色 前端控制器(Front Controller) - 一个处理器用于处理全部的用户请求 分发器(Dispatcher) - 把处理后的请求分发到对于的业务处理程序 视图(View) - 真正处理请求业务程序 下面是前端控制器的一个简单案例。 HomeView, StudentView 分别是具体业务处理程序。Dispatcher 用于把请求分发到对于的 View 中。FrontController 是所有用户请求的入口,进行身份验证、权限验证、记录或追踪请求日志。FrontControllerDemo 演示前端控制器模式。 代码实现 HomeView, StudentView 提供真正的业务处理逻辑 public class HomeView { public void show(){ System.out.println(“show Home view “); } } public class StudentView { public void show(){ System.out.println(“show student view “); } } Dispatcher 分发用户的请求到对应业务处理程序 public class Dispatcher { private StudentView studentView; private HomeView homeView; public Dispatcher(){ homeView = new HomeView(); ...

2017-02-12 · 1 min · 170 words · -

设计模式 – 策略/Strategy

设计模式 – 策略/Strategy 设计模式之Strategy(策略) 板桥里人 http://www.jdon.com 2002/03/30 Strategy策略模式是属于设计模式中 对象行为型模式,主要是定义一系列的算法,把这些算法一个个封装成单独的类. Stratrgy应用比较广泛,比如, 公司经营业务变化图, 可能有两种实现方式,一个是线条曲线,一个是框图(bar),这是两种算法,可以使用Strategy实现. 这里以字符串替代为例, 有一个文件,我们需要读取后,希望替代其中相应的变量,然后输出.关于替代其中变量的方法可能有多种方法,这取决于用户的要求,所以我们要准备几套变量字符替代方案. 首先,我们建立一个抽象类RepTempRule 定义一些公用变量和方法: public abstract class RepTempRule{ protected String oldString=""; public void setOldString(String oldString){ this.oldString=oldString; } protected String newString=""; public String getNewString(){ return newString; } public abstract void replace() throws Exception; } 在RepTempRule中 有一个抽象方法abstract需要继承明确,这个replace里其实是替代的具体方法. 我们现在有两个字符替代方案, 1.将文本中aaa替代成bbb; 2.将文本中aaa替代成ccc; 对应的类分别是RepTempRuleOne RepTempRuleTwo public class RepTempRuleOne extends RepTempRule{ public void replace() throws Exception{ //replaceFirst是jdk1.4新特性 newString=oldString.replaceFirst(“aaa”, “bbbb”) System.out.println(“this is replace one”); } } public class RepTempRuleTwo extends RepTempRule{ ...

2017-01-30 · 1 min · 152 words · -

设计模式 – State/状态模式

设计模式 – State/状态模式 State模式的定义: 不同的状态,不同的行为;或者说,每个状态有着相应的行为. 何时使用? State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了. 不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有可能要使用State. 是否使用? 在实际使用,类似开关一样的状态切换是很多的,但有时并不是那么明显,取决于你的经验和对系统的理解深度. 这里要阐述的是"开关切换状态" 和" 一般的状态判断"是有一些区别的, " 一般的状态判断"也是有 if..elseif结构,例如: if (which==1) state=“hello”; else if (which==2) state=“hi”; else if (which==3) state=“bye”; 这是一个 " 一般的状态判断",state值的不同是根据which变量来决定的,which和state没有关系.如果改成: if (state.euqals(“bye”)) state=“hello”; else if (state.euqals(“hello”)) state=“hi”; else if (state.euqals(“hi”)) state=“bye”; 这就是 “开关切换状态”,是将state的状态从"hello"切换到"hi",再切换到"“bye”;在切换到"hello",好象一个旋转开关,这种状态改变就可以使用State模式了. 如果单纯有上面一种将"hello"->“hi”->“bye”->“hello"这一个方向切换,也不一定需要使用State模式,因为State模式会建立很多子类,复杂化,但是如果又发生另外一个行为:将上面的切换方向反过来切换,或者需要任意切换,就需要State了. 请看下例: import java.awt.*; public class OldContext { private Color state = null; public void push() { //如果当前red状态 就切换到blue if (state == Color.red) state = Color.blue; //如果当前blue状态 就切换到green else if (state == Color.blue) state = Color.green; //如果当前black状态 就切换到red else if (state == Color.black) state = Color.red; //如果当前green状态 就切换到black else if (state == Color.green) state = Color.black; Sample sample = new Sample(state); sample.operate(); } public void pull() { //与push状态切换正好相反 if (state == Color.green) state = Color.blue; else if (state == Color.black) state = Color.green; else if (state == Color.blue) state = Color.red; else if (state == Color.red) state = Color.black; Sample sample2 = new Sample(state); sample2.operate(); } } 在上例中,我们有两个动作push推和pull拉,这两个开关动作,改变了Context颜色,至此,我们就需要使用State模式优化它. ...

2017-01-23 · 2 min · 394 words · -

系统架构图

系统架构图 系统架构图怎么画?系统架构图首先是人,人是构成系统架构图的核心,也就是系统架构师。IBM工程师的说明是: 架构师的主要责任是提供开发人员和项目经理之间的共用沟通媒体。他们负责让业务规则及需求与工程实践及限制相适应,以确保成功。 中文Wiki上的说明是: 系统架构师负责设计系统整体架构,从需求到设计的每个细节都要考虑到,把握整个项目,使设计的项目尽量效率高,开发容易,维护方便,升级简单。这两个部分加起来组成了系统架构师的定义。本文主要介绍系统架构图怎么画? 系统架构图怎么画?要画好系统架构图,首先明白系统架构图都有哪些,你要画的系统架构图属于?这是系统架构师工作内容与职责之基础。 http://chasefull.blog.51cto.com/6570525/1134536 http://blog.itpub.net/6517/viewspace-609654

2015-06-09 · 1 min · 8 words · -

委托模式

委托模式 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 · -

设计模式 – 模板方法, Template Method

设计模式 – 模板方法, Template Method http://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html 模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。 模板方法模式的结构 模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。 模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。 模板方法所代表的行为称为顶级行为,其逻辑称为顶级逻辑。 这里涉及到两个角色: 抽象模板(Abstract Template)角色有如下责任: ■定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。 ■定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。 具体模板(Concrete Template)角色又如下责任: ■实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。 ■每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法 (也就是顶级逻辑的组成步骤) 的不同实现,从而使得顶级逻辑的实现各不相同。 源代码 抽象模板角色类,abstractMethod()、hookMethod()等基本方法是顶级逻辑的组成步骤,这个顶级逻辑由templateMethod()方法代表。 按 Ctrl+C 复制代码 public abstract class AbstractTemplate { /** 模板方法 */ public void templateMethod(){ //调用基本方法 abstractMethod(); hookMethod(); concreteMethod(); } /** 基本方法的声明 (由子类实现) */ protected abstract void abstractMethod(); /** 基本方法(空方法) */ protected void hookMethod(){} /** 基本方法 (已经实现) */ private final void concreteMethod(){ //业务相关的代码 } } 按 Ctrl+C 复制代码 具体模板角色类,实现了父类所声明的基本方法,abstractMethod()方法所代表的就是强制子类实现的剩余逻辑,而hookMethod()方法是可选择实现的逻辑,不是必须实现的。 ...

2013-06-13 · 3 min · 534 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 · -

适配器模式 Adapter

适配器模式 Adapter 通常,客户类 (clients of class) 通过类的接口访问它提供的服务。有时,现有的类 (existing class) 可以提供客户类的功能需要,但是它所提供的接口不一定是客户类所期望的。这是由于现有的接口太详细或者缺乏详细或接口的名称与客户类所查找的不同等诸多不同原因导致的。 在这种情况下,现有的接口需要转化 (convert) 为客户类期望的接口,这样保证了对现有类的重用。如果不进行这样的转化,客户类就不能利用现有类所提供的功能。适配器模式 (Adapter Pattern) 可以完成这样的转化。适配器模式建议定义一个包装类,包装有不兼容接口的对象。这个包装类指的就是适配器 (Adapter) ,它包装的对象就是适配者(Adaptee)。适配器提供客户类需要的接口,适配器接口的实现是把客户类的请求转化为对适配者的相应接口的调用。换句话说: 当客户类调用适配器的方法时,在适配器类的内部调用适配者类的方法,这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器可以使由于借口不兼容而不能交互的类可以一起工作 (work together) 。 在上面讨论的接口: (1) 不是指在JAVA编程语言中接口的概念,虽然类的接口可以通过JAVA借扩来定义。 (2) 不是指由窗体和GUI控件所组成的GUI应用程序的用户接口。 (3) 而是指类所报漏的,被其他类调用的编程接口, 类适配器 (Class Adapter) VS对象适配器(Object Adapter) 适配器总体上可以分为两类??类适配器 (Class Adapter) VS对象适配器(Object Adapter) 类适配器 类适配器是通过继承类适配者类 (Adaptee Class) 实现的,另外类适配器实现客户类所需要的接口。当客户对象调用适配器类方法的时候,适配器内部调用它所继承的适配者的方法。 对象适配器 对象适配器包含一个适配器者的引用 (reference) ,与类适配器相同,对象适配器也实现了客户类需要的接口。当客户对象调用对象适配器的方法的时候,对象适配器调它所包含的适配器者实例的适当方法。 下表是类适配器 (Class Adapter) 和对象适配器(Object Adapter)的详细不同: 补充: 类适配器 (Class Adapter) 对象适配器(Object Adapter) 基于继承概念 利用对象合成 只能应用在适配者是接口,不能利用它子类的接口,当类适配器建立时,它就静态地与适配者关联 可以应用在适配者是接口和它的所有子类,因为适配器是作为适配者的子类,所以适配器可能会重载适配者的一些行为。 注意: 在JAVA中,子类不能重载父类中声明为final的方法。 不能重载适配者的方法。 ...

2012-10-18 · 2 min · 276 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 · -

创建者模式, 建造者模式, Builder

创建者模式, 建造者模式, Builder 定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 使用场景 多个部件或零件,都可以装配到一个对象中,但产生的结果又不相同时。 当初始化一个对象特别复杂的时候,比如参数多,而且很多参数都有默认值。 它分为抽象建造者 (Builder) 角色、具体建造者 (ConcreteBuilder) 角色、导演者 (Director) 角色、产品 (Product) 角色四个角色。 抽象建造者 (Builder) 角色: 给 出一个抽象接口,以规范产品对象的各个组成成分的建造。 具体建造者 (ConcreteBuilder) 角色: 要完成的任务包括: 1.实现抽象建造者Builder所声明的接口,给出一步一步地完成创建产品实例的操作。2.在建造过程完成后,提供产品的实例。 导演者 (Director) 角色: 担任这个角色的类调用具体建造者角色以创建产品对象。 产品 (Product) 角色: 产品便是建造中的复杂对象。 对于Builder模式很简单,但是一直想不明白为什么要这么设计,为什么要向builder要Product而不是向知道建造过程的Director要。刚才google到一篇文章,总算清楚了。在这里转贴一下这位richardluo的比喻。 简单地说,就好象我要一座房子住,可是我不知道怎么盖 (简单的砌墙,层次较低) ,也不知道怎么样设计 (建几个房间,几个门好看,层次较高) ,于是我需要找一帮民工,他们会砌墙,还得找个设计师,他知道怎么设计,我还要确保民工听设计师的领导,而设计师本身也不干活,光是下命令,这里砌一堵墙,这里砌一扇门,这样民工开始建设,最后,我可以向民工要房子了。在这个过程中,设计师是什么也没有,除了他在脑子里的设计和命令,所以要房子也是跟民工要,记住了! 以下是richardluo的代码,我根据他的思路加上了相应的注释。 定义工人接口,就是能够完成建造房子任务的人的通用要求。 // 工人接口,定义了各个工人所要进行的工所作。他们负责进行具体部件如窗户,地板的建造。 // 同时因为房子是民工建的,因此建设完成后由他把房子递交回房主 public interface Builder { public void makeWindow(); public void makeFloor(); public Room getRoom(); } 2. 定义设计师,他的职责是指挥房主指派给他的工人按照自己的设计意图建造房子。 ```java // 设计师。他知道房子应该怎么设计,但他不会自己去建造,而是指挥民工去建造。 public class Designer { // 指挥民工进行工作 public void order(Builder builder) { builder.makeWindow(); builder.makeFloor(); } } 民工,他负责具体事物的实施。 // 民工。负责进行具体部件如窗户,地板的建造。 //同时因为房子是民工建的,因此建设完成后由他把房子递交回房主 public class Mingong implements Builder { private String window=""; private String floor=""; public void makeWindow() { window=new String("window"); } public void makeFloor(){ floor=new String("floor"); } // 回交房子给房主 public Room getRoom() { if((!window.equals(""))&&(!floor.equals(""))) { System.out.println("room ready!"); return new Room(); } else return null; } } 房主,就是雇人,收房。 // 房主。房主的任务就是聘请一个民工,一个设计师,同时把民工给设计师指挥,督促设计师开展工作。最后从民工手上收房。 public class Client { public static void main(String[] args) { Builder mingong = new Mingong(); Designer designer = new Designer(); designer.order(mingong); mingong.getRoom(); } } 好了,我觉得这样大概能说明白了。不知各位觉得如何呢?或者有更好的应用场景解释,敬请赐教。 ...

2012-10-10 · 3 min · 468 words · -

原型模式 Prototype

原型模式 Prototype Prototype模式是一种对象创建型模式,它跟工厂模式,Builder模式等一样,都用来创建类的实例对象。 但Prototype模式的对象创建方法,具有以下特点: 由原型对象自身创建目标对象。也就是说,对象创建这一动作发自原型对象本身。 目标对象是原型对象的一个克隆。也就是说,通过Prototype模式创建的对象,不仅仅与原型对象具有相同的结构,还与原型对象具有相同的值。 根据对象克隆深度层次的不同,有浅度克隆与深度克隆。 简单一点说, Prototype模式提供一种方法,让类的对象可以实现对自身的复制。 Prototype模式的应用场景: 在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据。 希望对目标对象的修改不影响既有的原型对象 (深度克隆的时候可以完全互不影响) 。 隐藏克隆操作的细节。很多时候,对对象本身的克隆需要涉及到类本身的数据细节。 现实生活中,就有许多这样的例子: 生物细胞的自身复制;根据产品模型生产产品等等 Prototype模式的模型定义: Prototype { +clone():Prototype } 即: 原型类Prototype 提供clone()方法,实现对对象自身的复制 (克隆) 。 Prototype模式的实现范例 下面我们使用Prototype模式来实现细胞 (Cell) 的自身复制过程。 Java语言提供了对象复制的机制,Prototype模式的Java实现一般也通过实现Cloneable接口来实现。 这里我们也通过实现Cloneable接口来说明Prototype模式。 public class Cell implements Cloneable { //细胞壁 private String cellWall; //细胞膜 private String cellMembrane; //细胞组织 private String cellularTissue; ...//这里省略掉了对成员变量的setter/getter方法的定义 //细胞的自身复制 //这里重载了Obect#clone()方法,为了方便外部调用,把返回值由Object修改为Cell,并把访问级别设置为public public Cell clone() { try { //只需简单地调用super.clone();即可 return (Cell) super .clone(); } catch (CloneNotSupportedException e) { throw ( new InternalError(e.getMessage())); } } } //调用方: public class Client { public static void main(String[] args) { //准备原型细胞 Cell cell = new Cell(); cell.setCellWall("cell wall 1" ); ... //克隆原型细胞 Cell clonedCell = cell.clone(); ... //操作被克隆的细胞 (略) } } 这里使用了一个简单的例子说明了Prototype模式的对象创建过程与方法。里面省略了某些无关紧要的代码。

2012-10-10 · 1 min · 110 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)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。 分类 创建模式 Simple Factory Pattern 简单工厂模式 https://blog.wiloon.com/?p=1399 Factory Method Pattern 工厂方法 Abstract Factory Pattern 抽象工厂模式 prototype, 原型 Builder, 建造者 Singleton, 单例 结构模式 Facade, 外观 Proxy, 代理 Adapter, 适配器 Composite, 组合 Decorator, 装饰器 https://blog.wiloon.com/?p=847 Bridge, 桥接 Flyweight, 享元 行为模式 Template Method, 模板方法 https://blog.wiloon.com/?p=5526 Memento, 备忘录 Observer - 观察者 https://wiloon.com/observer Chain Of Responsibility - 责任链, 亦称: 职责链模式、命令链、CoR、Chain of Command、Chain of Responsibility Command, 命令模式 (别名: 动作模式(Action)或事务模式(Transaction)) State, 状态 - https://blog.wiloon.com/?p=9678 Strategy, 策略 Meidator, 中介者 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 · 386 words · -