设计模式之禅读书笔记1
来源:互联网 发布:龙泉刀剑章氏有淘宝吗 编辑:程序博客网 时间:2024/05/16 16:57
原型模式
实现Cloneable接口并重写clone()方法,就完成了原型模式。
通用源码:
public class ProtoTypeClass implements Cloneable{ @Override public ProtoTypeClass clone(){ ProtoTypeClass protoType = null; try{ protoType = (ProtoTypeClass)super.clone(); }catch(CloneNotSupportedException e){ //异常处理 } return protoType; }}
- 优点:原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多。尤其是要在一个循环体内产生大量的对象时。
- 缺点:逃避构造函数的约束。直接在内存中拷贝,构造函数是不会执行的。Object类的clone方法的原理就是从内存中以二进制流的方式进行拷贝,重新分配一个内存块。
- 应用场景:
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 通过new产生一个对象需要非常多繁琐的数据准备货访问权限。
- 一个对象多个修改者。有可能产生数据不一致的问题。可以考虑使用原型模式拷贝多个对象供调用者使用。
实际项目中原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone的方法创建一个对象,然后由工厂方法提供给调用者。
浅拷贝和深拷贝
浅拷贝:Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝。还是指向原生对象的内部地址。而其他的原始类型比如int,long,char等都会被拷贝,但对于String类型,java希望你把它认为是基本的原始类型,它是没有clone()方法的。处理机制也比较特殊,通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串。
注:使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;而是必须是一个可变的引用对象,而不是原始类型或不可变对象。
public class Thing implements Cloneable{ private ArrayList<String> arrayList = new ArrayList<String>(); @Override public Thing clone(){ Thing thing=null; try { thing = (Thing)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return thing; } public void setValue(String value){ this.arrayList.add(value); } public ArrayList<String> getValue(){ return this.arrayList; }}public static void main(String[] args) { Thing thing = new Thing(); thing.setValue("李四"); Thing cloneThing = thing.clone(); cloneThing.setValue("张三"); System.out.println(thing.getValue());//结果是[李四,张三] }
深拷贝:改下上面clone()方法的代码即可实现深拷贝。
public Thing clone(){ Thing thing=null; try { thing = (Thing)super.clone(); this.arrayList = (ArrayList<String>)this.arrayList.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return thing; }
注:要实现深拷贝,类的成员变量不要增加final关键字,否则会报错。
最佳实践:原型模式先产生出一个包含大量共有信息的类,然后可以拷贝出副本,修正细节信息,建立一个完整的个性对象。
中介者模式
迪米特法则认为每个类只和朋友类交流。
中介者模式定义:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示的相互作用,使其耦合松散,而且可以独立的改变他们之间的交互。
中介者模式通用类图:
ConcreteMediator—>Mediator<——-Colleague
Mediator:抽象中介者,定义统一的接口,用于各同事角色之间的通信。
Concrete Mediator:具体中介者,协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。
Colleague:每一个同事角色都知道中介者角色,每一个同事类的行为分为两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等。一种是必须依赖中介者才能完成的行为,叫做依赖方法。
通用代码:
public abstract class Mediator { //定义同事类 protected ConcreteColleague1 c1; protected ConcreteColleague2 c2; //通过getter/setter把同事类注入进来 public ConcreteColleague1 getC1() { return c1; } public void setC1(ConcreteColleague1 c1) { this.c1 = c1; } public ConcreteColleague2 getC2() { return c2; } public void setC2(ConcreteColleague2 c2) { this.c2 = c2; } //中介者模式的业务逻辑 public abstract void doSomething1(); public abstract void doSomething2();}public class ConcreteMediator extends Mediator { @Override public void doSomething1() { //调用同事类的方法 super.c1.selfMethod1(); super.c2.selfMethod2(); } public void doSomething2() { super.c1.selfMethod1(); super.c2.selfMethod2(); }}public abstract class Colleague { protected Mediator mediator; public Colleague(Mediator _mediator){ this.mediator = _mediator; }}public class ConcreteColleague1 extends Colleague { //通过构造函数传递中介者 public ConcreteColleague1(Mediator _mediator){ super(_mediator); } //自有方法 public void selfMethod1(){ //处理自己的业务逻辑 } //依赖方法 dep-method public void depMethod1(){ //处理自己的业务逻辑 //自己不能处理的业务逻辑,委托给中介者处理 super.mediator.doSomething1(); }}public class ConcreteColleague2 extends Colleague { public ConcreteColleague2(Mediator _mediator){ super(_mediator); } public void selfMethod2(){ //处理自己的业务逻辑 } public void depMethod2(){ //处理自己的业务逻辑 super.mediator.doSomething2(); }}
- 优点:减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者。降低了类间的耦合。
- 缺点:中介者会膨胀的很大,同事类越多,中介者的逻辑就越复杂。
- 应用:中介者模式的使用要量力而行。适用于多个对象之间的紧密耦合的情况。紧密耦合的标准是:在类图中出现了蜘蛛网结构。把蜘蛛网梳理为星型结构。
- 实际应用:
机场调度中心。
MVC框架:struts的C(Controller)就是一个中介者。把Model和Vie
w隔离开,协调M和V协同工作,减少他们之间的依赖。
媒体网关、中介服务等 - 最佳实践:
- N个对象之间产生了相互的依赖关系(N>2)
- 多个对象有依赖关系,但是依赖的行为尚不确定或者有发生改变的可能。可使用中介者模式降低变更引起的风险扩散。
- 产品开发。把中介者模式应用到产品中,可以提升产品的性能和扩展性。
命令模式
定义:将一个请求封装成一个对象,从而让你使用不同的请求吧客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
命令模式的通用类图:
Receiver:接受者角色。干活的角色。命令传到这里是应该被执行的。
Command命令角色:需要执行的所有命令都在这里执行。
Invoker调用者角色:接收到命令并执行命令。
通用代码
public abstract class Receiver{ //抽象接受者,定义每个接受者都必须完成的业务 public abstract void doSomething();}public class ConcreteReciver1 extends Receiver{ //每个接收者必须处理一定的业务逻辑 public void doSomething(){ }}public class ConcreteReciver2 extends Receiver{ public void doSomething(){ }}public abstract class Command { //每个命令类都必须有一个执行命令的方法 public abstract void execute();}public class ConcreteCommand1 extends Command { //对哪个receiver进行命令处理 private Receiver receiver; //构造函数传递接收者 public ConcreteCommand1(Receiver _receiver){ this.receiver = _receiver; } //必须执行一个命令 public void execute() { this.receiver.doSomething(); }}public class ConcreteCommand2 extends Command { private Receiver receiver; public ConcreteCommand2(Receiver _receiver){ this.receiver = _receiver; } public void execute() { //ÒµÎñ´¦Àí this.receiver.doSomething(); }}public class Invoker { private Command command; //接收命令 public void setCommand(Command _command){ this.command = _command; } //执行命令 public void action(){ this.command.execute(); }}public class Client { public static void main(String[] args) { Invoker invoker = new Invoker(); Receiver receiver = new ConcreteReciver1(); Command command = new ConcreteCommand1(receiver); invoker.setCommand(command); invoker.action(); }}
优点:
1. 类间解耦,调用者角色与接收者角色之间没有任何依赖关系。调用者实现功能时只需调用Command抽象类的execute方法就可以了。
2. 可扩展性:Command的子类非常容易扩展。
3. 命令模式可以结合责任链模式,实现命令族解析,结合模板方法模式,则可以减少Command子类的膨胀问题。
缺点:Command的子类会膨胀。
- 设计模式之禅读书笔记1
- 设计模式之禅读书笔记
- 《设计模式之禅》读书笔记
- 《设计模式之禅》读书笔记
- 《设计模式之禅》读书笔记-策略模式
- 读书笔记之设计模式
- 读书笔记 之 设计模式
- 《设计模式之禅》之读书笔记
- 《设计模式之禅》读书笔记(二)
- 《设计模式之禅》读书笔记(三)
- 《设计模式之禅》读书笔记(四)
- 《设计模式之禅》读书笔记(五)
- 《设计模式》读书笔记之1 — 序言
- 读书笔记之head first设计模式1
- 《设计模式之禅》读书笔记(二)之工厂方法模式
- 《设计模式之禅》读书笔记(四)之抽象工厂模式
- 设计模式-读书笔记1
- 单例模式----设计模式之禅读书笔记
- 蓝桥杯练习系统算法训练——质数的乘积
- 使用nginx反向代理docker中的git和redmine
- 7-包装器函数+Match对象+Date对象+note
- Java缩略图生成库之Thumbnailator应用说明
- lintcode 第12题
- 设计模式之禅读书笔记1
- js局部刷新
- iOS 使用UIBezierPath, CAShapeLayer, CABasicAnimation动态绘制折线
- Java中的file.separator
- 笔记
- 一个简单实用的cURL模拟http请求的函数
- Leetcode 435. Non-overlapping Intervals
- Caused by: java.sql.SQLException: sql injection violation, syntax error: ERROR. token : DESC
- js中的instanceof运算符