??xml version="1.0" encoding="utf-8" standalone="yes"?>
计数代理模式在客户对象调用服务提供者对象上Ҏ的前后执行诸如日志(loggingQ和计数QcountingQ一pd附加
功能时很有用。计C理模式徏议把q些附加功能装在一个单独的对象Q这个对象就是指计数代理对象Q而不是把q些附加的功能实现放到服务提供者的内部。良
好的对象设计的一个特征就是对象要专注于提供特定的功能。换句话_理想的对象不应该做各U不相干的事情。把诸如日志QloggingQ和计数
QcountingQ等cM的功能封装ؓ一个单独的对象Q而让服务提供者对象仅提供它自q特定功能。也是_只允许服务提供者对象执行定义良好、特?
的Q务?br>
计数代理被设计成可以被客戯问的与服务提供者具有相同接口的对象。客户对象不是直接访问服务提供者,而是调用计数代理对象上的ҎQ计C理执行必要的U录日志QloggingQ和计数QcountingQ功能后Q再把方法调用传递给服务提供着对象。如?
Figure1: Generic Class Association When the Counting Proxy Pattern Is Applied
下面的例子说明了如何在应用程序中利用计数代理?br>
例子Q?br>
让我们设计一个Orderc,cdơ如?QOrderIF接口声明了getAllOrdersd数据库中所有订单的单方法?br>
Figure2: Order Class Hierarchy
public interface OrderIF {
public Vector getAllOrders();
}
作ؓgetAllOrdersҎ实现的一部分QOrdercd用了FileUtil工具cMorder.txt文g中读取订单项?br>
public class Order implements OrderIF {
public Vector getAllOrders() {
FileUtil fileUtil = new FileUtil();
Vector v = fileUtil.fileToVector("orders.txt");
return v;
}
}
让我们假定在调用getAllOrders()Ӟ需要把取数据文件所p的时间和记录条数要记录的log日志文g中?br>
q个附加的功能可以设计一个单独的OrderProxycL实现Q它与真实对象Order一样实现OrderIF接口。这样保证了OrderProxy对象提供l客户与真实对象Order一L接口。如?
public class OrderProxy implements OrderIF {
private int counter = 0;
public Vector getAllOrders() {
Order order = new Order();
counter++;
long t1 = System.currentTimeMillis ();
Vector v = order.getAllOrders();
long t2 = System.currentTimeMillis();
long timeDiff = t2 ? t1;
String msg = "Iteration=" + counter + "::Time=" + timeDiff + "ms";
//log the message
FileUtil fileUtil = new FileUtil();
fileUtil.writeToFile("log.txt?msg, true, true);
return v;
}
}
客户对象MainApp想调用真实对象Order一栯用OrderProxy对象上的getAllOrders()ҎQOrderProxy对象
传递这个调用给真实对象Order,计算d所有订单所p的时间ƈ使用FileUtil帮助cd其纪录的log日志文g中。在q个q程中,
OrderProxy扮演者计C理的角色?br>
public class MainApp {
public static void main(String[] args) {
OrderIF order = new OrderProxy();
Vector v = order.getAllOrders();
v = order.getAllOrders();
v = order.getAllOrders();
v = order.getAllOrders();
}
}
]]>
* cd实现动态类调用
* @param instance 一个信息获取类的实?br> * @param methodName Ҏ名称
* @param classes 参数cd数组
* @param objects 参数数组
* @return Object q回了方法执行后的结?br> */
private Object invokeInstanceMethod(
final Object instance, final String methodName,
final Class[] classes, final Object[] objects) {
try {
Method method;
try {
method = instance.getClass().getDeclaredMethod(methodName, classes);
}
catch (NoSuchMethodException e) {
method = instance.getClass().getMethod(methodName, classes);
}
method.setAccessible(true);
return method.invoke(instance, objects);
}
catch (NoSuchMethodException e) {
throw new RuntimeException(e.getMessage());
}
catch (IllegalAccessException e) {
throw new RuntimeException(e.getMessage());
}
catch (InvocationTargetException e) {
throw new RuntimeException(e.getTargetException().getMessage());
}
}
/* Q非 JavadocQ?br> * @see com.eware.dataBaseOperation.dataOperateToolKit
* .dataBaseOperate.InterFaceGetOwnerDataInfo#getOwnerTables()
*/
/**
* 实现了接口方法获取当前用h有表的信?br> */
public ResultSet getOwnerTables() {
// TODO 自动生成Ҏ存根
return (ResultSet)invokeInstanceMethod(goic, "getOwnerTables",
new Class[]{}, new Object[]{});
}
1. 普通的非内部类不能被声明ؓprivate?/span>protectedQ否则就失去了创cȝ意义。但是内部类通常可以被声明ؓprivate?/span>protectedcdQ因样可以防止他人对该内部类实现的功能进行修改,辑ֈ隐藏实现l节的目的。例如:
class Fruit {
private class Weight {
private String i;
private Weight(String j) {
i = j;
}
public String read() {
return i;
}
}
}
class test {
public static void main(String[] args) {
Fruit f = new Fruit();
f.Weight w = f.new Weight(); //不能讉Kprivatec,如果Weight?/span>protectedcd则可?/span>
}
}
2. 在方法或某控制语?/span>(if/for/while{?/span>)的作用域内定义内部类Q将只能在该范围内调用内部类的方法和成员变量?/span>
3. 匿名内部cL一U特D的内部c,如果希望它用一个在其外部定义的对象Q那么编译器会要求其参数引用?/span>final的?/span>
public class Fruit {
public Tea cont(final int j) {
return new Tea() {
private int i = j;
public int read() {
return i;
}
}; //注意q里的分?/span>
}
public static void main(String[] args) {
Fruit f = new Fruit();
Tea t = f.cont;
}
}
而当Ҏcont(final int j)中的参数j只是被传递到匿名cM的构造器Ӟ可以不用被声明ؓfinalcdQ如return new Tea(j)。这里提C匿名内部cȝ构造器Q那么它是怎么被初始化的呢Q?/span>
public class Fruit {
public Tea cont(int j) {
return new Tea(j) {
System.out.println(j);
};
}
}
q可以这样初始化匿名内部c:
public class Fruit {
public Tea cont(final int j) {
return new Tea(j) {
int i;
// 初始化匿名内部类
{
i = j;
System.out.print(i);
}
};
}
}
Ҏcont()可以被称为实例初始化ҎQ得匿名内部类通过构造器而被初始化,在实际应用中Q我们不能重载实例初始化ҎQ因为匿名内部类只能有一个构造方法?/span>class Mammal extends Animal {
int heartRate;
//l承weight
...
void breathe() {
...
}
//l承eat
}
cd能扩展另外的一个类。只支持单承(single inheritanceQ?/p>
子类可以q一步派生子cR?/p>
public abstract class IDEOperation { private Compiler cmp; private Runtime rtime; public void compile(String javaFile) { cmp.compile(javaFile); } public void run(String classFile) { rtime.run (classFile); } //to be delayed until needed. public abstract void generateDocs(String javaFile); public IDEOperation() { cmp = new Compiler(); rtime = new Runtime(); } } |
public class RealProcessor extends IDEOperation { JavaDoc jdoc; public RealProcessor() { super(); jdoc = new JavaDoc(); } public void generateDocs(String javaFile) { jdoc.generateDocs(javaFile); } } |
![]() Figure 25.1: IDEOperation Class Hierarchy |
public class ProxyProcessor extends IDEOperation { private RealProcessor realProcessor; public void generateDocs(String javaFile) { /* In order to generate javadocs the proxy loads the actual object and invokes its methods. */ if (realProcessor == null) { realProcessor = new RealProcessor(); } realProcessor.generateDocs(javaFile); } } |
public class Client { public static void main(String[] args) { /* At this point objects required for the compile and run operations are created, but not the objects that provide the generate Javadoc functionality. */ IDEOperation IDE = new ProxyProcessor(); IDE.compile("test.java"); IDE.run("test.class"); /* The Javadoc functionality is accessed For the first time and hence the Object offering the Javadoc generation Functionality is loaded at this point. */ IDE.generateDocs("test.java"); } } |
1. 贡献法则(Contributin Rule):一切皆是A?/font>
2.遵@法则(Conformance Rule):插g必须遵@预期的接?/font>
3.׃n法则(sharing Rule):增加,不要取代
4.有样学样法则(Monkey See/Monkey Do Rule):遇到问题?首先复制cM插g的结?/font>
5.相关性法?Relevance Rule):只有在操作有可能成功时才昄你所贡献的操?/font>
6.整合法则(Integration Rule):要整合不要分?/font>
7.责Q法则(Responsibility Rule):明确 指出你开发的插g旉题的源头
8.针对API契约~程法则(Program To API Contract Rule):首先查Eclipse API契约,然后后针对契U编E?/font>
9."其他"法则(Other Rule):让用户可以选择所有东?但把那些通常不用于当前视角的选项攑֜Other...对话框中
10.IResource适配法则(Adapt To IResource Rule):应该量为领域对象定义IResource适配?/font>
11.分层法则(Strata Rule):语a无关的功能与特定于具体语a的功能分开,核心功能与UI功能分开
12.使用q诏性法?User Continuity Rule):在多ơ回话期?应该保持用户界面状态一?/font>
public class PassHandles {
static void f(PassHandles h) {
System.out.println("h inside f(): " + h);
}
public static void main(String[] args) {
PassHandles
p = new PassHandles();
System.out.println("p inside main(): " + p);
f(p);
}
}
toString Ҏ会在打印语句里自动调用,而PassHandles 直接从Object l承Q没有toString 的重新定义?br>因此Q这里会采用toString 的Object 版本Q打印出对象的类Q接着是那个对象所在的位置Q不是句柄,?br>是对象的实际存储位置Q。输出结果如下:
p inside main(): PassHandles@1653748
h inside f() : PassHandles@1653748
可以看到Q无论p q是h 引用的都是同一个对象。这比复制一个新的PassHandles 对象有效多了Q我们?br>一个参数发l一个方法。但q样做也带来了另一个重要的问题Q别名问?/p>
1.邀h?Invitation Rule):可能的邀请别Zؓ你的作品做出贡献
2.懒加载法?Lazy Loading Rule):只有在真正需要的时候才加蝲插g
3.安全q_法则(Safe Platform Rule):作ؓ扩展点的提供?你必M护好自己,不要让扩展者的误操作给你造成损失
4.公^竞赛法则(Fair Play Rule):所有用者遵守同L游戏规则,包括我自?/p>
5.明确扩展法则(Explicit Extension Rule):明确说明q_的什么地方可供扩?/p>
6.发散性法?Diversity Rule):一个扩展点接纳多个扩展
7.良好防M法则(Good Fences Rule):如果要交出程序的控制?首先保护好你自己
8.用户军_法则(User Arbitration Rule):如果有多个选择,q户决定用哪?/p>
9.明确API法则(Explicit API Rule):API与插件内部用的cd开
10.E_性法?Stability Rule):如果你已l开始邀请其他h作出贡献,׃要再改变规则
11.保守API法则(Defensive API Rule):只暴露你有信心的API,但同时也要做好准备暴露更多的API,因ؓ使用者会邀请你q样?/p>
后调用Q何需要的Ҏ