`
里克尔奇
  • 浏览: 35634 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

设计模式之模板方法模式

    博客分类:
  • J2SE
阅读更多
   很多时候我们都在使用模板方法模式而没有意识到自己应经使用了这个模板模式。模板模式是基于继承的代码复用的技术,模板模式的结构和用法也是面向对象的核心。

    模板方法模式是类的的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。

    模板方法模式涉及到两个角色:即抽象模板角色和具体模板角色,具体模板角色是对抽象模板角色的继承。

1、抽象模板角色

     (1)定义了一个或多个抽象操作,以便子类实现。这些抽象操作叫做原操作或者基本操作,他们是一个顶级逻辑的组成部分。顶级逻辑,即顶级行为的的逻辑,顶级行为,即模板方法所代表的行为。

     (2)定义并实现了一个模板方法。这个模板方法一般是一个具体的方法,他给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现,顶级逻辑也有可能调用一些具体的方法,但肯定得有这个抽象模板的抽象方法,否则失去了模板方法模式的意义。

2、具体模板角色

    (1)实现父类所定义的一个或多个抽象方法,他们是顶级逻辑的组成部分。

    (2)每一个抽象模板角色都可以有任意多个具体模板角色与其对应,而每一个具体模板角色都可以给出抽象模板(即它的抽象的父类)中的抽象方法的不同实现,从而使得顶级逻辑的实现各部相同。
这是一个关于读取的一个例子:我们可以读取一个本地文件,或者是读取一个网页文件内容,它们大体都需要打开、读取、和关闭几个步骤。只不过读取本地文件和读取网页文件的各个步骤不同,所以各个步骤可由具体模板来实现。
    抽象模板
   
public abstract class AbstractRead {
    protected String resource;
    public void getContent() { // Template Method
        if(open()) {
            readContent();
            close();
        }
    }
    public void setResource(String s) {
        resource = s;
    }
    protected abstract boolean open();
    protected abstract void readContent();
    protected abstract void close();
}
   

读取本地文件的具体模板


import java.io.*;

public class ReadFile extends AbstractRead {
    private BufferedReader in = null;
    public ReadFile() {
    }
    public ReadFile(String fileName) {
        resource = fileName;
    }
    protected boolean open() {
        try {
            in = new BufferedReader(new FileReader(resource));
        } catch(IOException e) {
            System.out.println("Can not open file!");
            return false;
        }
        return true;
    }
    protected void readContent() {
        try {
            if(in != null) {
                String str;
                while((str = in.readLine()) != null) {
                     System.out.println(str);  
                }
            }
        } catch(IOException e) {
            System.out.println("Read file error !");
        }
    }
    protected void close() {
        if(in != null) {
            try {
                in.close();
            } catch(IOException e) {
                System.out.println("IO error !");
            }
        }
    }
}

读取网页文件的具体模板代码
import java.io.*;
import java.net.*;

public class ReadHtml extends AbstractRead {
    private URLConnection conn;
    private BufferedReader in;
    
    public ReadHtml() {
    }
    public ReadHtml(String s) {
        resource = s;
    }

    public boolean open() {
        try {
            URL url = new URL(resource);
            conn = url.openConnection();
            in = new BufferedReader (
                            new InputStreamReader(conn.getInputStream()));
        } catch (MalformedURLException e) {
            System.out.println("Uable to connect URL:" + resource);
            return false;
        } catch (IOException e) {
            System.out.println("IOExeption when connecting to URL" + resource);
            return false;
        }
        return true;
    }
    protected void readContent() {
        try {
            if(in != null) {
                String str;
                while((str = in.readLine()) != null) {
                     System.out.println(str);  
                }
            }
        } catch(IOException e) {
            System.out.println("Read file error !");
        }
    }
    protected void close() {
        if(in != null) {
            try {
                in.close();
            } catch(IOException e) {
                System.out.println("IO error !");
            }
        }
    }
    
}

接下来是模拟客户端的一个测试类
public class Test  {
    public static void main(String[] args) {
        // 我的文件路径实在linux下,如果是windows下可使用文件的绝对路径即可
        String fileName = "/root/test.txt";
        String url = "http://java.iteye.com/";
        
        AbstractRead fileRead = new ReadFile();
        AbstractRead htmlRead = new ReadHtml();

        fileRead.setResource(fileName);
        htmlRead.setResource(url);
        
        System.out.println("-----  Read from a file  -----");        
        fileRead.getContent();
        System.out.println("-----  Read from a url  -----");
        htmlRead.getContent();
    }
}

模板方法适用于以下情况:

  1) 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。

  2) 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。其实这可以说是一种好的编码习惯了。

  3) 控制子类扩展。模板方法只在特定点调用操作,这样就只允许在这些点进行扩展。比如上面runBare()方法就只在runTest前面适用setUp方法。如果你不愿子类来修改你的模板方法定义的框架,你可以采用两种方式来做:一是在API中不体现出你的模板方法;二、将你的模板方法置为final就可以了。

  可以看出,使用模板方法模式可以将代码的公共行为提取出来,达到复用的目的。而且,在模板方法模式中,是由父类的模板方法来控制子类中的具体实现。这样你在实现子类的时候,根本不需要对业务流程有太多的了解。

java语言中使用过的模板方法模式
   ClassLoader类,当我们要自定义一个类加载器的时候,我们需要定义一个自己定义一个类加载器,这个类需要继承自这个ClassLoader类,这个类就是抽象模板,在自定一的类加载的中我们只需要在自定义的类加载器的这个类中实现findClass方法即可,
public Class findClass(String name) {
             byte[] b = loadClassData(name);
             return defineClass(name, b, 0, b.length);
         }


类加载器的加载过程是由ClassLoader抽象类定义好的,即抽象模板的顶级行为。关于java类加载的的详细介绍可以参考这篇博文http://idealab.iteye.com/blog/358592
0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics