??xml version="1.0" encoding="utf-8" standalone="yes"?>
Composite比较Ҏ理解Q想到Composite应该想到树形结构图。组合体内这?strong style="COLOR: red">对象都有共同接口,当组合体一个对象的Ҏ被调用执行时QComposite?strong style="COLOR: red">遍历(Iterator)整个树Şl构,L同样包含q个Ҏ的对象ƈ实现调用执行。可以用牵一动百来Ş宏V?/span>
所以Composite模式使用到Iterator模式Q和Chain of Responsibility模式cM?/span>
三、Composite好处
四、如何用Composite
---- 以上内容摘自Jdon|站的《Gof 23U设计模式》系列文?br />
一个二叉树的例子: public abstract class Component { public abstract Component addChild(Component leftChild, Component rightChild); public String getName() { public void getTreeInfo() { public abstract int getLength(); public class Leaf extends Component { private Component leaf = null; public Leaf(String name) { public Component addChild(Component leftChild, Component rightChild) { public String getName() { public int getLength() { public static void main(String[] args) { public class Tree extends Component { private Component leftChild; private Component rightChild; public Tree(String name, Component leftChild, Component rightChild) { public Tree(String name) { public Component addChild(Component leftChild, Component rightChild) { public String getName() { public void getTreeInfo() public int getLength() { public static void main(String[] args) { public class Test { public Test() { public static void main(String[] args) {
一?引言
]]>
]]>
]]>
对象以树Şl构l织h,以达成“部分-整体?的层ơ结构,使得客户端对单个对象和组合对象的使用h一致?/strong>.
二、Composite模式的特?/strong>
1.使客L调用单,客户端可以一致的使用l合l构或其中单个对象,用户׃必关p自己处理的是单个对象还是整个组合结构,q就化了客户端代码?br />2.更容易在l合体内加入对象部g. 客户端不必因为加入了新的对象部g而更改代码?/span>
首先定义一个接口或抽象c,q是设计模式通用方式了,其他设计模式Ҏ口内部定义限制不多,Composite却有个规定,那就是要在接口内部定义一个用于访问和理Compositel合体的对象们(或称部gComponentQ?
五、Composite模式的分?/strong>
·Composite模式的结构:
基类/接口(构g抽象)
|
|--- 原子构g(extends 基类 / implements 接口)
|
|--- l合构g(extends 基类 / implements 接口)
|--- 原子构g1
|--- 原子构g2
|--- l合构g3
|--- 原子构g3-1
|--- 原子构g3-2
·Composite模式的特点:
·Composite模式一般都有一个抽象类或接口来表示最基本的构件?br /> ·Composite模式一般都׃cd象构成:表示单个元素的对?Primitive)和表C多个元素组合的对象(Composite)
·Composite模式下Primitive和Composite对象都承或实现上层接口或父c?br /> ·Composite模式下每个构仉含有三个基础ҎQadd(构g)、remove(构g)、iterator()
·Composite对象含有一个用来保存其下所有基元素的的集合Q例如:VectorQArrayListQHashMap
·Composite对象的方法被调用时一般都会引起其下所有基元素相同Ҏ的调用,即递归调用?br />
·Composite模式中Primitive对象和Composite对象的方法区别:
·add(构g)Q如果是基础对象Q则此方法直接返回falseQ如果是l合对象Q则先添加新构g然后q回true
·remove(构g)Q如果是基础对象Q则此方法直接返回falseQ如果是l合对象Q则先删除构件然后返回true
·iterator()Q如果是基础对象Q则此方法直接返回nullQ如果是l合对象Q则q回一个包含所有对象的集合
·客户端调用Composite模式的代码示例:
·创徏一个原子构件对?br /> ·创徏一个组合构件对?br /> ·调用l合构g对象的add/removeҎd/删除对象
·调用l合够对象的iteratoreҎq代昄对象
本文摘自Q?a href="/pengpenglin/archive/2008/01/21/176675.html">http://www.aygfsteel.com/pengpenglin/archive/2008/01/21/176675.html
l:
1.Component 是抽象组?br />Tree 和Leaf l承Component
private String name; //树或叶子的名U?br />addChild(Component leftChild,Component rightChild);
//l一个树上加上一个左孩子Q一个右孩子
getName(){return name;}
getTreeInfo(){} //得到树或叶子的详l信?br />getLength(); //得到树的高度
2.Tree 二叉树,一个左孩子Q一个右孩子
3.Leaf 是叶子节?br />4.Test 是测试节?
/** Component.java **************/
package binarytree;
private String name;
return name;
}
}
}
/** Leaf.java **************/
package binarytree;
private String name;
this.name = name;
}
return this;
}
return name;
}
return 1;
}
}
}
/** Tree.java **************/
package binarytree;
private String name;
this.name = name;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
this.name = name;
this.leftChild = null;
this.rightChild = null;
}
this.leftChild = leftChild;
this.rightChild = rightChild;
return this;
}
return name;
}
// 得到树或叶子的详l信?br /> // 先打印自q名字Q再遍例左孩子,再遍例右孩子
// 如果左孩子或叛_子是树,递归调用
{
System.out.println(" this trees name is " + getName());
if (this.leftChild instanceof Leaf) {
System.out.println(getName() + "s left child is "
+ this.leftChild.getName() + ",it is a Leaf");
}
if (this.leftChild instanceof Tree) {
System.out.println(getName() + "s left child is "
+ this.leftChild.getName() + ",it is a Tree");
this.leftChild.getTreeInfo();
}
if (this.leftChild == null) {
System.out.println(getName() + "s left child is a null");
}
if (this.rightChild instanceof Leaf) {
System.out.println(getName() + "s right child is "
+ this.rightChild.getName() + ",it is a Leaf");
}
if (this.rightChild instanceof Tree) {
System.out.println(getName() + "s right child is "
+ this.rightChild.getName() + ",it is a Tree");
this.rightChild.getTreeInfo();
}
if (this.rightChild == null) {
System.out.println(getName() + "s right child is a null");
}
// System.out.println(getName()+"s 高度 ?"+getLength());
}
// 比较左孩子或叛_子的高度Q谁大,+1 q回
// I孩子的处理
if (this.leftChild == null) {
if (this.rightChild == null)
return 1;
else
return this.rightChild.getLength() + 1;
} else {
if (this.rightChild == null) {
return this.leftChild.getLength() + 1;
} else {
if ((this.leftChild.getLength()) >= (this.rightChild
.getLength()))
return this.leftChild.getLength() + 1;
else
return this.rightChild.getLength() + 1;
}
}
}
}
}
/** Test.java 试c?**************/
package binarytree;
}
Component tree = new Tree("luopeng");
Component left_child = new Leaf("luopeng1");
Component right_child = new Leaf("luopeng2");
tree = tree.addChild(left_child, right_child);
// tree=tree.addRightChild(right_child);
tree.getTreeInfo();
Component tree1 = new Tree("luopeng2");
tree1.addChild(tree, left_child);
tree1.getTreeInfo();
Component tree2 = new Tree("luopeng3");
tree2.addChild(tree, null);
tree2.getTreeInfo();
Component tree4 = new Tree("luopeng4");
tree4.addChild(null, tree);
tree4.getTreeInfo();
System.out.println(tree4.getName() + "的高度是 " + tree4.getLength());
}
}
]]>
q代q个名词对于熟悉Java的h来说l对不陌生。我们常怋用JDK提供的P代接口进行java collection的遍历:
Iterator it = list.iterator();
while(it.hasNext()){
//using “it.next();”do some businesss logic
}
而这是关于q代器模式应用很好的例子?br />
二?定义与结?/strong>
q代器(IteratorQ模式,又叫做游标(CursorQ模式。GOFl出的定义ؓQ提供一U方法访问一个容器(containerQ对象中各个元素Q而又不需暴露该对象的内部l节?br />
从定义可见,q代器模式是为容器而生。很明显Q对容器对象的访问必然涉及到遍历法。你可以一股脑的将遍历Ҏ塞到容器对象中去Q或者根本不L供什么遍历算法,让用容器的己去实现d。这两种情况好像都能够解决问题?br />
然而在前一U情况,容器承受了过多的功能Q它不仅要负责自己“容器”内的元素维护(d、删除等{)Q而且q要提供遍历自n的接口;而且׃遍历状态保存的问题Q不能对同一个容器对象同时进行多个遍历。第二种方式倒是省事Q却又将容器的内部细节暴露无遗?br />
而P代器模式的出玎ͼ很好的解决了上面两种情况的弊端。先来看下P代器模式的真面目吧?
q代器模式由以下角色l成Q?br />
1) q代器角ԌIteratorQ:q代器角色负责定义访问和遍历元素的接口?br />
2) 具体q代器角ԌConcrete IteratorQ:具体q代器角色要实现q代器接口,q要记录遍历中的当前位置?br />
3) 容器角色QContainerQ:容器角色负责提供创徏具体q代器角色的接口?br />
4) 具体容器角色QConcrete ContainerQ:具体容器角色实现创徏具体q代器角色的接口——这个具体P代器角色于该容器的结构相兟?br />
q代器模式的cd如下Q?br />
从结构上可以看出QP代器模式在客户与容器之间加入了P代器角色。P代器角色的加入,可以很好的避免容器内部l节的暴Ԍ而且也得设计符号“单一职责原则”?br />
注意Q在q代器模式中Q具体P代器角色和具体容器角色是耦合在一L——遍历算法是与容器的内部l节紧密相关的。ؓ了客户E序从与具体q代器角色耦合的困境中q出来Q避免具体P代器角色的更换给客户E序带来的修改,q代器模式抽象了具体q代器角Ԍ使得客户E序更具一般性和重用性。这被称为多态P代?br />
三?举例
׃q代器模式本w的规定比较松散Q所以具体实C׃花八门。我们在此仅举一例,Ҏ不能实现方式一一呈现。因此在举例前,我们先来列D下P代器模式的实现方式?
1QP代器角色定义了遍历的接口Q但是没有规定由谁来控制q代。在Java collection的应用中Q是由客L序来控制遍历的进E,被称为外部P代器Q还有一U实现方式便是由q代器自w来控制q代Q被UCؓ内部q代器。外部P代器要比内部q代器灵zR强大,而且内部q代器在java语言环境中,可用性很弱?br />
2Q在q代器模式中没有规定谁来实现遍历法。好像理所当然的要在P代器角色中实现。因为既便于一个容器上使用不同的遍历算法,也便于将一U遍历算法应用于不同的容器。但是这样就破坏掉了容器的封装——容器角色就要公开自己的私有属性,在java中便意味着向其他类公开了自qU有属性?br />
那我们把它放到容器角色里来实现好了。这栯P代器角色p架空Z仅存放一个遍历当前位|的功能。但是遍历算法便和特定的容器紧紧l在一起了?br />
而在Java Collection的应用中Q提供的具体q代器角色是定义在容器角色中的内部类。这样便保护了容器的装。但是同时容器也提供了遍历算法接口,你可以扩展自qq代器?br />
好了Q我们来看下Java Collection中的q代器是怎么实现的吧?br />//q代器角Ԍ仅仅定义了遍历接?p>public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
//容器角色Q这里以ListZ。它也仅仅是一个接口,׃|列出来?br />//具体容器角色Q便是实CList接口的ArrayList{类。ؓ了突出重点这里指|列和P代器相关的内?br />//具体q代器角Ԍ它是以内部类的Ş式出来的。AbstractList是ؓ了将各个具体容器角色的公共部分提取出来而存在的?/p>
public abstract class AbstractList extends AbstractCollection implements List {
…?
//q个便是负责创徏具体q代器角色的工厂Ҏ
public Iterator iterator() {
return new Itr();
}
//作ؓ内部cȝ具体q代器角?/p>
private class Itr implements Iterator {
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public Object next() {
checkForComodification();
try {
Object next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
至于q代器模式的使用。正如引a中所列那P客户E序要先得到具体容器角色Q然后再通过具体容器角色得到具体q代器角艌Ӏ这样便可以使用具体q代器角色来遍历容器了…?br />
四?实现自己的P代器
在实现自qq代器的时候,一般要操作的容器有支持的接口才可以。而且我们q要注意以下问题Q?
在P代器遍历的过E中Q通过该P代器q行容器元素的增减操作是否安全呢Q?br />
在容器中存在复合对象的情况,q代器怎样才能支持深层遍历和多U遍历呢Q?br />
以上两个问题对于不同l构的容器角Ԍ各不相同Q值得考虑?br />
五?适用情况
׃面的讲述Q我们可以看P代器模式l容器的应用带来以下好处Q?br />
1) 支持以不同的方式遍历一个容器角艌Ӏ根据实现方式的不同Q效果上会有差别?br />
2) 化了容器的接口。但是在java Collection中ؓ了提高可扩展性,容器q是提供了遍历的接口?br />
3) 对同一个容器对象,可以同时q行多个遍历。因为遍历状态是保存在每一个P代器对象中的?br />
由此也能得出q代器模式的适用范围Q?br />
1) 讉K一个容器对象的内容而无需暴露它的内部表示?br />
2) 支持对容器对象的多种遍历?br />
3) 为遍历不同的容器l构提供一个统一的接口(多态P代)?br />
实例Q?br />
public class IteratorDemo {
private List<String> strList;
public IteratorDemo() {
strList = new ArrayList<String>();
}
public void add(String item) {
strList.add(item);
}
public String remove(int index) {
String item = strList.get(index);
strList.remove(index);
return item;
}
public Iterator<String> iterator() {
return new Iterator<String>() {
// 游标
private int cursor = 0;
public boolean hasNext() {
return cursor < strList.size();
}
public String next() {
return strList.get(cursor++);
}
public void remove() {
}
};
}
public static void main(String[] args) {
IteratorDemo demo = new IteratorDemo();
demo.add("1");
demo.add("2");
demo.add("3");
demo.add("4");
Iterator<String> iterator = demo.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
使用频率 | 所属类?/td> | 模式名称 | 模式 | 单定?/td> |
5 | 创徏?/td> | Singleton | 单例模式 | 保证一个类只有一个实例,q提供一个访问它的全局讉K炏V?/td> |
5 | l构?/td> | Composite | 复合模式 | 对象组合成树Şl构以表C部分整体的关系QComposite使得用户对单个对象和l合对象的用具有一致性?/td> |
5 | l构?/td> | FASADE | 面模?/td> | 为子pȝ中的一l接口提供一致的界面Qfasade提供了一高层接口Q这个接口得子pȝ更容易用?/td> |
5 | l构?/td> | Proxy | 代理 | 为其他对象提供一U代理以控制对这个对象的讉K |
5 | 行ؓ?/td> | Iterator | q代?/td> | 提供一个方法顺序访问一个聚合对象的各个元素Q而又不需要暴露该对象的内部表C?/td> |
5 | 行ؓ?/td> | Observer | 观察?/td> | 定义对象间一对多的依赖关p,当一个对象的状态发生改变时Q所有依赖于它的对象都得到通知自动更新?/td> |
5 | 行ؓ?/td> | Template Method | 模板Ҏ | 定义一个操作中的算法的骨架Q而将一些步骤gq到子类中,TemplateMethod使得子类可以不改变一个算法的l构卛_以重定义该算法得某些特定步骤?/td> |
4 | 创徏?/td> | Abstract Factory | 抽象工厂 | 提供一个创Zpd相关或相互依赖对象的接口Q而无L定它们的具体cR?/td> |
4 | 创徏?/td> | Factory Method | 工厂Ҏ | 定义一个用于创建对象的接口Q让子类军_实例化哪一个类QFactory Method使一个类的实例化延迟C子类?/td> |
4 | l构?/td> | Adapter | 适配?/td> | 一cȝ接口转换成客户希望的另外一个接口,Adapter模式使得原本׃接口不兼容而不能一起工作那些类可以一起工作?/td> |
4 | l构?/td> | Decrator | 装饰模式 | 动态地l一个对象增加一些额外的职责Q就增加的功能来_Decorator模式相比生成子类更加灉|?/td> |
4 | 行ؓ?/td> | Command | 指o模式 | 一个请求封装ؓ一个对象,从而你可以用不同的请求对客户q行参数化,对请求排队和记录h日志Q以及支持可撤销的操作?/td> |
4 | 行ؓ?/td> | State | 状态模?/td> | 允许对象在其内部状态改变时改变他的行ؓ。对象看hg改变了他的类?/td> |
4 | 行ؓ?/td> | Strategy | {略模式 | 定义一pd的算法,把他们一个个装hQƈ使他们可以互相替换,本模式得算法可以独立于使用它们的客戗?/td> |
3 | 创徏?/td> | Builder | 生成?/td> | 一个复杂对象的构徏与他的表C相分离Q得同L构徏q程可以创徏不同的表C?/td> |
3 | l构?/td> | Bridge | 桥模?/td> | 抽象部分与它的实现部分相分,使他们可以独立的变化?/td> |
3 | 行ؓ?/td> | Chain of Responsibility | 职责?/td> | 使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系 |
2 | 创徏?/td> | Prototype | 原型 | 用原型实例指定创建对象的U类Qƈ且通过拯q些原型来创建新的对象?/td> |
2 | l构?/td> | Flyweight | 享元 | |
2 | 行ؓ?/td> | Mediator | 中介?/td> | 用一个中介对象封装一些列的对象交互?/td> |
2 | 行ؓ?/td> | Visitor | 讉K?/td> | 表示一个作用于某对象结构中的各元素的操作,它你可以在不改变各元素cȝ前提下定义作用于q个元素的新操作?/td> |
1 | 行ؓ?/td> | Interpreter | 解释?/td> | l定一个语aQ定义他的文法的一个表C,q定义一个解释器Q这个解释器使用该表C来解释语言中的句子?/td> |
1 | 行ؓ?/td> | Memento | 备忘?/td> | 在不破坏对象的前提下Q捕获一个对象的内部状态,q在该对象之外保存这个状态?/td> |
转自2004q?期《CSDN开发高手?/p>
EventListenerList是特别需要说明的Q它内部使用一个Object数组存放监听器。但是它q不是直接存放,而是先存监听器的classcdQ然后再存监听器本n。即存放(MyListener.class , myListener)。一个Object数组可以存放多种cd的ListenerQ如果还有一U监听器AnotherListenerQ那?AnotherListener.class , anotherListener)也可以存放。无论增删都是两个对象一同被d或删除。上qC码中的listenerList.add(MyListener.class , listener)或listenerList.remove(MyListener.class , listener)Q以及fireDoMyAction()中的"i-=2"Q就是这h作的?/strong>
/**
* 定义Client使用的与特定领域相关的接?br /> */
public interface Target {
void sampleOperation1();
void sampleOperation2();
}
/**
* 定义一个已l存在的接口Q这个接口需要适配
*/
public class Adaptee {
public void sampleOperation1() {
// ......
}
}
/**
* 对Adaptee与Target接口q行适配
*/
public class Adapter extends Adaptee implements Target {
public void sampleOperation2() {
// ......
}
}
二、对象适配?br /> 与类的适配器模式一P对象适配器模式把适配的类的API转换成ؓ目标cȝAPIQ与cȝ适配器模式不同的是,对象的适配器模式不是用承关p连接到Adapteec,而是使用委派关系q接到AdapteecR示意代码如下:
/**
* 定义Client使用的与特定领域相关的接?br /> */
public interface Target {
void sampleOperation1();
void sampleOperation2();
}
/**
* 定义一个已l存在的接口Q这个接口需要适配
*/
public class Adaptee {
public void sampleOperation1() {
// ......
}
}
/**
* 对Adaptee与Target接口q行适配
*/
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
super();
this.adaptee = adaptee;
}
public void sampleOperation1() {
adaptee.sampleOperation1(); // 看点
}
public void sampleOperation2() {
// ......
}
}
c适配器模式和对象适配器模式的异同QTarget接口和Adapteec都相同Q不同的是类适配器的Adapterl承Adaptee实现TargetQ对象适配器的Adapter实现Target聚集Adaptee?br />
适配器模式的用意是将接口不同而功能相同或者相q的两个接口加以转换?br />
代理模式的作用是Qؓ其他对象提供一U代理以控制对这个对象的讉K。在某些情况下,一个客户不x者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用?/span>
代理模式一般涉及到的角色有Q?/span>
抽象角色 Q声明真实对象和代理对象的共同接口;
代理角色 Q代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在Q何时刻都能代替真实对象。同Ӟ代理对象可以在执行真实对象操作时Q附加其他的操作Q相当于对真实对象进行封装?/span>
真实角色 Q代理角色所代表的真实对象,是我们最l要引用的对象?/span> ( 参见文献 1)
以下以?/span> Java 与模式》中的示例ؓ例:
抽象角色Q?/span>
abstract public class Subject
{
abstract public void request();
}
真实角色Q实C Subject ?/span> request() Ҏ?/span>
public class RealSubject extends Subject
{
public RealSubject()
{
}
public void request()
{
System.out.println("From real subject.");
}
}
代理角色Q?/span>
public class ProxySubject extends Subject
{
private RealSubject realSubject; // 以真实角色作Z理角色的属?/span>
public ProxySubject()
{
}
public void request() // 该方法封装了真实对象?/span> request Ҏ
{
preRequest();
if( realSubject == null )
{
realSubject = new RealSubject();
}
realSubject.request(); // 此处执行真实对象?/span> request Ҏ
postRequest();
}
private void preRequest()
{
//something you want to do before requesting
}
private void postRequest()
{
//something you want to do after requesting
}
}
客户端调用:
Subject sub=new ProxySubject();
Sub.request();
׃上代码可以看出,客户实际需要调用的?/span> RealSubject cȝ request() ҎQ现在用 ProxySubject 来代?/span> RealSubject c,同样辑ֈ目的Q同时还装了其他方?/span> (preRequest(),postRequest()) Q可以处理一些其他问题?/span>
另外Q如果要按照上述的方法用代理模式,那么真实角色必须是事先已l存在的Qƈ其作ؓ代理对象的内部属性。但是实际用时Q一个真实角色必d应一个代理角Ԍ如果大量使用会导致类的急剧膨胀Q此外,如果事先q不知道真实角色Q该如何使用代理呢?q个问题可以通过 Java 的动态代理类来解冟?/span>
2. 动态代理类
Java 动态代理类位于 Java.lang.reflect 包下Q一般主要涉及到以下两个c:
(1). Interface InvocationHandler Q该接口中仅定义了一个方?/span> Object Q?/span> invoke(Object obj,Method method, Object[] args) 。在实际使用ӞW一个参?/span> obj 一般是指代理类Q?/span> method 是被代理的方法,如上例中?/span> request() Q?/span> args Ҏ的参数数l。这个抽象方法在代理cM动态实现?/span>
(2).Proxy
Q该cd为动态代理类Q作用类g上例中的
ProxySubject
Q其中主要包含以下内容:
Protected Proxy(InvocationHandler h) Q构造函敎ͼ估计用于l内部的 h 赋倹{?/span>
Static Class getProxyClass (ClassLoader loader, Class[] interfaces) Q获得一个代理类Q其?/span> loader 是类装蝲器, interfaces 是真实类所拥有的全部接口的数组?/span>
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) Q返回代理类的一个实例,q回后的代理cd以当作被代理cM?/span> ( 可用被代理cȝ?/span> Subject 接口中声明过的方?/span> ) ?/span>
所?/span>
Dynamic Proxy
是这样一U?/span>
class
Q它是在q行时生成的
class
Q在生成它时你必L供一l?/span>
interface
l它Q然后该
class
宣U它实现了这?/span>
interface
。你当然可以把该
class
的实例当作这?/span>
interface
中的M一个来用。当然啦Q这?/span>
Dynamic Proxy
其实是一?/span>
Proxy
Q它不会替你作实质性的工作Q在生成它的实例时你必须提供一?/span>
handler
Q由它接实际的工作?/span>
(
参见文献
3)
在用动态代理类Ӟ我们必须实现 InvocationHandler 接口Q以W一节中的示例ؓ例:
抽象角色 ( 之前是抽象类Q此处应改ؓ接口 ) Q?/span>
public interface Subject
{
abstract public void request();
}
具体角色 RealSubject Q同上;
代理角色Q?/span>
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
public class DynamicSubject implements InvocationHandler {
private Object sub;
public DynamicSubject() {
}
public DynamicSubject(Object obj) {
sub = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling " + method);
method.invoke(sub,args);
System.out.println("after calling " + method);
return null;
}
}
该代理类的内部属性ؓ Object c,实际使用旉过该类的构造函?/span> DynamicSubject(Object obj) 对其赋|此外Q在该类q实C invoke ҎQ该Ҏ中的
method.invoke(sub,args);
其实是调用被代理对象的要被执行的ҎQ方法参?/span> sub 是实际的被代理对象, args 为执行被代理对象相应操作所需的参数。通过动态代理类Q我们可以在调用之前或之后执行一些相x作?/span>
客户?/span> Q?/span>
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Client
{
static public void main(String[] args) throws Throwable
{
RealSubject rs = new RealSubject(); // 在这里指定被代理c?/span>
InvocationHandler ds = new DynamicSubject(rs); // 初始化代理类
Class cls = rs.getClass();
// 以下是分解步?/span>
/*
Class c = Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces()) ;
Constructor ct=c.getConstructor(new Class[]{InvocationHandler.class});
Subject subject =(Subject) ct.newInstance(new Object[]{ds});
*/
// 以下是一ơ性生?/span>
Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(),ds );
subject.request();
}
通过q种方式Q被代理的对?/span> (RealSubject) 可以在运行时动态改变,需要控制的接口 (Subject 接口 ) 可以在运行时改变Q控制的方式 (DynamicSubject c?/span> ) 也可以动态改变,从而实C非常灉|的动态代理关p?/span> ( 参见文献 2) ?/span>
private Singleton(){}
//在自己内部定义自׃个实例,是不是很奇怪?
//注意q是private 只供内部调用
private static Singleton instance = new Singleton();
//q里提供了一个供外部讉K本class的静态方法,可以直接讉K
public static Singleton getInstance() {
return instance;
}
}
2.懒汉式单例类
public class Singleton2 {
//U有的默认构造子
private Singleton2() {}
//注意Q这里没有final
private static Singleton2 single;
//只实例化一?/span>
static{
single = new Singleton2();
}
//静态工厂方法?/span>
public synchronized static Singleton2 getInstance() {
if (single == null) {
single = new Singleton2();
}
return single;
}
}
上面l出懒汉式单例类实现里对静态工厂方法用了同步化,以处理多U程环境。有些设计师在这里徏议用所谓的"双重查成?.必须指出的是Q?双重查成?不可以在Java 语言中用。不十分熟悉的读者,可以看看后面l出的小节?同样Q由于构造子是私有的Q因此,此类不能被ѝ饿汉式单例cd自己被加载时将自己实例化。即便加载器是静态的Q在饿汉式单例类被加载时仍会自己实例化。单从资源利用效率角度来Ԍq个比懒汉式单例cȝ差些。从速度和反应时间角度来Ԍ则比懒汉式单例类E好些。然而,懒汉式单例类在实例化Ӟ必须处理好在多个U程同时首次引用此类时的讉K限制问题Q特别是当单例类作ؓ资源控制器,在实例化时必然涉及资源初始化Q而资源初始化很有可能耗费旉。这意味着出现多线E同旉ơ引用此cȝ机率变得较大?br />
3.单例模式 -- 双重查锁机制
public class DoubleLockSingleton {
private static DoubleLockSingleton instance = null;
private DoubleLockSingleton() {
}
public static DoubleLockSingleton getInstance()
{
if (instance == null)
{
synchronized(DoubleLockSingleton .class) { //1
if (instance == null) //2
instance = new DoubleLockSingleton (); //3
}
}
return instance;
}
}
Singleton的好处还在于可以节省内存Q因为它限制?br />实例的个敎ͼ有利于Java垃圾回收Qgarbage collectionQ?br />
4.发明者是Google公司的Bob lee:
public class Singleton {
static class SingletonHolder {
static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}