11 代理模式
代理要做的就是控制和管理访问。
你的客户对象所做的就像是在做远程方法调用,但其实只是调用本地堆中的“代理”对象上的方法,再由代理处理所有网络通信的低层细节。
Java的RMI提供了客户辅助对象和服务辅助对象,为客户辅助对象创建和服务对象相同的方法。RMI的好处在于你不必亲自写任何网络或I/O代码。客户程序调用远程方法(即真正的服务所在)就和在运行在客户自己的本地JVM上对对象进行正常方法调用一样。
RMI将客户辅助对象称为stub(桩),服务辅助对象成为skeleton(骨架)。
定义代理模式
代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
public class NonOwnerInvocationHandler implements InvocationHandler {PersionBean person;public NonOwnerInvocationHandler(PersionBean person) {this.person = person;}public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException {try{if(method.getName().startsWith("get")){return method.invoke(person, args);} else if(method.getName().equals("setHotOrNotRating")){return method.invoke(person, args);} else if(method.getName().startsWith("set")) {return IllegalAccessException();}} catch(InvocationTargetException e) {e.printStackTrace();}return null;}
}
PersionBean getNonOwnerProxy(PersionBean person) {return (PersionBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),new NonOwnerInvocationHandler(person));
}
真实世界中还有很多代理:
12 复合模式(模式的模式)
模式通常被一起使用,并被组合在同一个设计解决方案中。复合模式在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题。
public class QuackCounter implements Quackable {Quackable duck;static int numberOfQuacks;//Observable observable;public QuackCounter(Quackable duck) {this.duck = duck;observable = new Observable(this);}public void quack() {duck.quack();numberOfQuacks++;//notifyObservers();}public static int getQuacks(){return numberOfQuacks;}public void registerObserver(Observer observer) {duck.registerObserver(observer);}public void notifyObservers() {duck.notifyObservers();}
}
注:Observable表示被观察者类,Observer表示观察者类。
public class Flock implements Quackable {ArrayList ducks = new ArrayList();public void add(Quackable duck) {ducks.add(duck);}public void quack() {Iterator iterator = ducks.iterator();while(iterator.hasNext()) {Quackable duck = (Quackable)iterator.next();duck.quack();}}public void registerObserver(Observer observer) {Iterator iterator = ducks.iterator();while(iterator.hasNext()) {Quackable duck = (Quackable)iterator.next();duck.registerObserver(observer);}}public void notifyObservers() {}
}
复合模式之王
复合模式:Model-View-Controller,MVC。
MVC是由数个设计模式结合起来的模式,当你通过研究设计模式来学习MVC时,突然之间它开始变得清晰明了。
具体来说,MVC涉及下面的设计模式:
Model 2是MVC在Web上的调整:
观察者和策略都隐藏起来了,但实际上还是有的。
复合模式结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题。
13 与设计模式相处
定义设计模式
模式是在某情境(context)下,针对某问题的某种解决方案。
第一个也是最权威的设计模式目录是《设计模式:可复用面向对象软件的基础》,由 Gamma、Helm、Johnson 和 Vlissides(Addison Wesley 出版社)所著。这个目录阐述了23个基本的设计模式。
如何当一个设计模式模式的作家?
- 做好家庭作业。发掘新模式之前,你必须先精通现有的模式。许多模式看起来像是全新的,但是事实上只是现有模式的变种。通过研究现有的模式,你可以比较容易地识别模式,并且学会将某一模式与其他模式联系起来。
- 花时间反思与评估。
- 将你的想法写在纸上,好让其他人能够理解。
- 让其他人使用你的模式,然后再持续改进。
- 不要忘了三次规则。除非你的模式已经再真实世界的三个方案中被成功地采用了,否则就不够资格被当成模式。
我画的:
迭代器:在对象的集合之中游走,而不暴露集合的实现。
工厂方法:由子类决定要创建的具体类是哪一个。
组合:客户用一致的方式处理对象集合和单个对象。
抽象工厂:允许客户创建对象的家族,而无需指定他们的具体类。
答案:
根据模式目标分为三个不同的类目:创建型、行为型和结构型。
反模式告诉你如何采用一个不好的解决方案解决一个问题。
原本的解决方案:
反正就使用熟悉的技术好了。将熟悉的技术强迫性地用在许多问题上,甚至在明显不适当地地方也照用。
重构的解决方案:
开发人员通过教育、培训和读书会,可以学会新的解决方案。
剩下的模式
还有一些不太常用的模式。
桥接
桥接:使用桥接模式不只改变你的实现,也改变你的抽象。
现在你有了两个层次结构,其中一个是遥控器,而另一个是平台特定的电视机实现。有了桥接的存在,你就可以独立地改变这两个层次。
生成器
生成器:使用生成器模式封装一个产品地构造过程,并允许按步骤构造。
我们将旅游规划的创建过程,封装到一个对象中(此对象被称为生成器),然后让客户调用生成器为它创建旅游计划。
责任链
责任链:当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式(Chain of Responsibility Pattern)。
蝇量模式
蝇量模式:如想让某个类的一个实例能用来提供许多“虚拟实例”,就使用蝇量模式。
只用一个树实例和一个客户对象来维护“所有”树的状态。
// TreeManager.java
public class TreeManager {private Tree[][] treeArray;public TreeManager(int rows, int cols) {this.treeArray = new Tree[rows][cols];}public void displayTrees() {for (int i = 0; i < treeArray.length; i++) {for (int j = 0; j < treeArray[i].length; j++) {if (treeArray[i][j] != null) {treeArray[i][j].display(i, j, calculateAge(i, j));}}}}private int calculateAge(int x, int y) {// 示例:假设树龄是基于位置的简单计算return x + y;}
}// Tree.java
public class Tree {public void display(int x, int y, int age) {System.out.println("Displaying tree at (" + x + ", " + y + ") with age " + age);// 这里可以添加更复杂的显示逻辑}
}// 主程序
public class Main {public static void main(String[] args) {TreeManager manager = new TreeManager(3, 3);// 假设已经初始化了treeArray中的某些树对象manager.displayTrees();}
}
解释器
解释器:使用解释器模式为语言创建解释器。
要想解释这种语言,就调用每个表达式类型的interpret()方法。此方法需要传入一个上下文(Context)——也就是我们正在解析的语言字符串输入流——然后进行比对并采取适当的动作。
中介者
中介者:使用中介者模式来集中相关对象之间复杂的沟通和控制方式。
**中介者内包含了整个系统的控制逻辑。**当某装置需要一个新的规则时,或者是一个新的装置被加入系统内,其所有需要用到的逻辑也都被加入了中介者内。
备忘录
备忘录:当你需要让对象返回之前的状态时(例如,你的用户请求撤销),就使用备忘录模式。
备忘录模式两个目标:
- 储存系统关键对象的重要状态
- 维护关键对象的封装
原型
原型:当创建给定类的实力的过程很昂贵或很复杂时,就使用原型模式。
原型模式允许你通过复制现有的实例来创建新的实例。这个模式的重点在于,客户的代码在不知道要实例化何种特定类的情况下,可以制造出新的实例。
访问者
访问者:当你想要为一个对象的组合增加新的能力,且封装并不重要时,就使用访问者模式。