zoukankan      html  css  js  c++  java
  • Java设计模式-模板模式

    介绍:模板模式定义了一个模板抽象类,这个抽象类中定义了方法调用的形式,顺序。子类通过重写对方法进行实现,但是调用方式不能改变。

    模板模式中的模板中定义了核心的代码骨架,一些有着不同方式实现的代码放在子类中,模板模式规定了方法执行的方式或者可以说是方法的执行顺序,执行结构,使得子类只能遵守这些规定。

    模板模式解决了很多代码在子类中通用。每次业务相同的代码,用户每次还要重写这些一样的代码,现在将这些通用的代码提取出来,放在一个抽象类中,在抽象类中规定方法执行的方式,一些具体实现不一样的方法定义为抽象方法,由子类通过继承抽象类实现这些抽象方法。也可以说是把通用的算法抽象出来。

    把固定的部分封装起来,对于可变的部分用户可以进行扩展,提取出代码的公共部分放在父类,行为由父类控制,子类负责实现可变的部分。

    在tomcat中就有模板模式的应用,在用户写的Servlet中的doget和dopost方法就是子类中重写的方法,HttpServlet中的service方法定义了方法执行的方式,以下是HttpServlet中service方法的源码,方法中定义了每个方法执行的顺序,方式。也就是规定了核心,用户需要对那些服务定义自己的代码。

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }
    
                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }
    
    }

    假设我们去了饭店,干什么,当然是去吃饭喽,我们到饭店吃饭得有个流程吧,首先我们到了饭店,饭店需要为你找座位吧,当你坐下之后,服务员给你一张菜单,让你点菜,这都是固定的顺序,但是你点什么菜不是饭店规定好的,可以随意点,点完之后服务员会把点的这些菜提交给后厨,后厨做好之后服务员端上来,吃完之后就要到前台结账买单。除了顾客点菜之外,剩下的步骤都是一套固定的流程,我们就可以定义一个模板类,规定好饭店的这些流程,只有点餐这个流程不需要具体规定,留给顾客自己选择。

    定义模板类:饭店中时规定了方法执行的流程和具体操作,但是顾客点菜是顾客自己的行为,不需要规定

    package demo_template;
    
    public abstract class Template {
    
        //服务员为顾客选择座位
        private void selectSeat() {
            System.out.println("选择一个座位");
        }
    
        //服务员给顾客菜单
        private void passMenu() {
            System.out.println("递菜单");
        }
    
        //假设顾客只点了A,B,C三个菜
        public abstract void selectA();
    
        public abstract void selectB();
    
        public abstract void selectC();
    
        //服务员提交菜单
        private void submitMenu() {
            System.out.println("提交菜单");
        }
    
        //上菜
        private void serving() {
            System.out.println("上菜");
        }
        //顾客买单
        private void pay() {
            System.out.println("顾客买单");
        }
    
        protected void service() {
            selectSeat();
            passMenu();
            this.selectA();
            this.selectB();
            this.selectC();
            submitMenu();
            serving();
            pay();
    
        }
    
    }
    

    定义第一个顾客:顾客只负责点菜,其他不需要关心

    package demo_template;
    
    public class First extends Template {
    
        @Override
        public void selectA() {
            System.out.println("地三鲜");
        }
    
        @Override
        public void selectB() {
            System.out.println("大米饭");
        }
    
        @Override
        public void selectC() {
            System.out.println("橙汁");
        }
    }
    

    第二位顾客:

    package demo_template;
    
    public class Second extends Template {
        @Override
        public void selectA() {
            System.out.println("大米饭");
        }
    
        @Override
        public void selectB() {
            System.out.println("糖醋鲤鱼");
        }
    
        @Override
        public void selectC() {
            System.out.println("地三鲜");
        }
    }
    

    测试类:

    package demo_template;
    
    public class Test {
    
        public static void main(String[] args) {
            System.out.println("第一位顾客:");
            Template first = new First();
            first.service();
            System.out.println("---------------------");
            System.out.println("第二位顾客:");
            Template second = new Second();
            second.service();
        }
    }
    

    测试类用到了多态,我们创建的对象是First和Second的,类型是Template的,模板类中的三个点菜方法是用的this调用,this代表当前对象,当前对象是谁的,当然是First和Second的。

    输出:

    第一位顾客:
    选择一个座位
    递菜单
    地三鲜
    大米饭
    橙汁
    提交菜单
    上菜
    顾客买单
    ---------------------
    第二位顾客:
    选择一个座位
    递菜单
    大米饭
    糖醋鲤鱼
    地三鲜
    提交菜单
    上菜
    顾客买单

    优点:

    1、封装不变部分,扩展可变部分。

    2、提取公共代码,便于维护。

    3、行为由父类控制,子类实现。

    缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

    使用场景:

    1、有多个子类共有的方法,且逻辑相同。

    2、重要的、复杂的方法,可以考虑作为模板方法。


    参考:

    http://blog.csdn.net/lovelion/article/details/8299794

    http://www.runoob.com/design-pattern/template-pattern.html

  • 相关阅读:
    几种常用类的学习
    类,接口
    方法
    数组使用
    条件控制与循环
    类型转换,运算符
    Java基本类型
    SVN基本使用
    【转】MySQL的btree索引和hash索引的区别
    常用命令(java、linux)
  • 原文地址:https://www.cnblogs.com/duzhentong/p/7816582.html
Copyright © 2011-2022 走看看