初识设计模式

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 ----百科

今天记录下最近遇到的几个设计模式:

1.观察者(observer)模式

在java中gui的实现使用了观察者模式,观察者模式中几个关键的角色是:事件源、事件 、观察者。用windows窗口关闭这个最简单例子简单描述下三者之间的关系:

 

 1 public class Observer {
2 public static void main(String[] args) {
3 Frame f = new Frame("test");
4 f.setBounds(300, 300, 303, 100);
5 f.setVisible(true);
6 f.addWindowListener(new myWindowListener());
7 }
8
9 }
10 class myWindowListener implements WindowListener {
11 @Override
12 public void windowOpened(WindowEvent e) {System.out.println("opened"); }
13 @Override
14 public void windowClosing(WindowEvent e) {System.exit(0);}
15 @Override
16 public void windowClosed(WindowEvent e) {System.out.println("closed"); }
17 @Override
18 public void windowIconified(WindowEvent e) {System.out.println("iconified"); }
19 @Override
20 public void windowDeiconified(WindowEvent e) {System.out.println("deiconified"); }
21 @Override
22 public void windowActivated(WindowEvent e) {System.out.println("activated"); }
23 @Override
24 public void windowDeactivated(WindowEvent e) {System.out.println("deactivated"); }
25
26 }

在这个例子中,frame是事件源;对frame的各种操作产生不同的事件;而通过frame的addXXXListener绑定对不同的事件的不同处理。在这里,我们只绑定了关于对window操作的一个监听器,用来监听如接口中的那些事件,具体事件是怎么发生的呢?是系统底层实现的,当Listener关注的事件在绑定的对象上发生的时候,就会自动“唤醒”监听器,并传入发生的时间的信息,比如WindowEvevt,封装了发生点的信息,而且会自动调用发生点的函数。比如我们关闭窗口的时候,会调用closing函数。当让这时候就会有新的不方便了,有时候我只关心某些事件,但是接口提供了所有的事件,我们每个都去实现的话会很麻烦,还好,JDK提供了对所有接口空实现的一个类adapter类,我们一般用的时候只要重写我们关心的那个adapter的对应的函数就行了。

  

2.工厂(factory)模式 

 

一般来说我们会将类的共有特性抽象为一个接口,所有有这个特性的类去继承这个方法。如:

 1 interface Pet {
2 void feed();
3 }
4
5 class Dog implements Pet{
6 @Override
7 public void feed() {
8 System.out.println("feed meat");
9 }
10 }
11
12 class Cat implements Pet{
13 @Override
14 public void feed() {
15 System.out.println("feed fish");
16 }
17 }

当我们要“生产”具体的某个宠物的时候,可以直接通过new产生新的对象,这样我们就无法避免不同的类产生不同的对象,因此我们就需要在创建一个类,这个类专门用来生产宠物,即工厂,要产生实例,必须通过工厂,不能私自产生,而具体产生一个(单例)还是多个,则由工厂说了算。

 1 abstract class Factory {
2 abstract Pet creat();
3 }
4
5 class DogFactory extends Factory{
6 Dog d = new Dog();
7 Pet creat(){
8 return d;
9 }
10 }
11
12 class CatFactory extends Factory{
13 Cat c = new Cat();
14 Pet creat(){
15 return c;
16 }
17 }

这样我们将pet的生产抽象为一个抽象的工厂类,具体的pet生产则有自己特定的工厂生产,这样我们使用的时候就可以尽少修改的实现对具体的类的生产:

 

1 public static void main(String[] args) {
2 Factory factory = new CatFactory();//只需具体的生产工厂即可
3 Pet p1 = factory.creat();
4 p1.feed();
5 Pet p2 = factory.creat();
6 p2.feed();
7 System.out.println(p1 == p2);
8 }

这样,我们可以将具体的factory比如CatFactory写到配置文件中,通过反射直接实现“生产”。

 1 public static void main(String[] args) throws Exception{
2 Properties pro = new Properties();
3 try {
4 //通过classloader获得classpath得到配置文件,配置文件中类名为全称
5 pro.load(TestFactory.class.getClassLoader().getResourceAsStream("in.txt"));
6 } catch (IOException e) {
7 e.printStackTrace();
8 }
9 String factoryStr = pro.getProperty("factory");
10 System.out.println(factoryStr);
11 Factory factory = null;
12 try {
13 factory = (Factory) Class.forName(factoryStr).newInstance();
14 } catch (Exception e) {
15 e.printStackTrace();
16 }//只需具体的生产工厂即可
17 Pet p1 = factory.creat();
18 p1.feed();
19 Pet p2 = factory.creat();
20 p2.feed();
21 System.out.println(p1 == p2);
22 }

3.代理(proxy)模式

假设这样一种情况,我们有一个方法method,现在我们需要在不修改method源码的情况下,对在method的前后增加一些代码功能,比如打印,计时,检测等。这样我们在不修改代码的同时增加了自己的功能,就叫代理,我们实现功能的时候用代理类的方法就可以在原方法的基础上添加了自己的功能。同时,从另外一个维度上来说一个功能,如打印或计时,我们需要在不同的方法上都实现。java提供了proxy类实现代理操作。

 1 public class testProxy {
2 public static void main(String[] args) throws Exception {
3 /*Class class1 = Proxy.getProxyClass(Pet.class.getClassLoader(), Pet.class);
4 //class只有一个形参为InvocationHandler的构造方法
5 Constructor constructor = class1.getConstructor(InvocationHandler.class);
6 Pet p = (Pet)constructor.newInstance(new InvocationHandler1());*/
7
8 Pet p = (Pet) Proxy.newProxyInstance(Pet.class.getClassLoader(),
9 new Class[]{Pet.class}, new InvocationHandler1());
10 p.feed();//调用feed的时候调用了代理
11 System.out.println(p.getIntro(100));
12 }
13 }
14 class InvocationHandler1 implements InvocationHandler{
15 Pet pet = new Cat();
16 @Override
17 /*这里的形参proxy是调用的object,比如此例中是pet p。
18 因为p的所有方法都经过了代理,所以如果在invoke中调用外部方法(toString hashcode equals),则会死循环导致堆栈溢出。*/
19 public Object invoke(Object proxy, Method method, Object[] args)
20 throws Throwable {
21 System.out.println(method.getName());
22 if(args != null){
23 for(Object o : args){
24 if(o.equals(100)){
25 o = 3000;
26 }
27 }
28 }
29 Object object = method.invoke(pet, args);
30 System.out.println("-------------");
31 return object;
32 }
33 }
34 interface Pet {
35 void feed();
36 String getIntro(int test);//测试有返回值有形参的函数
37 }
38 class Dog implements Pet{
39 @Override
40 public void feed() {
41 System.out.println("feed meat");
42 }
43 @Override
44 public String getIntro(int test) {
45 return "i am dog:" + test;
46 }
47 }
48 class Cat implements Pet{
49 @Override
50 public void feed() {
51 System.out.println("feed fish");
52 }
53 @Override
54 public String getIntro(int test) {
55 return "i am cat:" + test;
56 }
57 }

这里我们invoke函数前后的处理代码还是静态代码,以后实现配置文件动态添加代码后,就有更大的灵活性了。

posted @ 2012-04-06 19:43  ruidge  阅读(187)  评论(0编辑  收藏  举报