Windows环境下实现设计模式——模板方法模式(JAVA版)

 我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下Windows环境下如何编程实现模板方法模式(设计模式)。

不知道大家有没有这样的感觉,看了一大堆编程和设计模式的书,却还是很难理解设计模式,无从下手。为什么?因为你看的都是理论书籍。

我今天就在Windows操作系统上安装好JAVA的IDE编程工具,并用JAVA语言来实现一个模板方法模式,真实的实现一个,你看懂代码后,自然就明白了。

模板方法模式Template Method Pattern  (行为型设计模式)

定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

上面定义听懂了吗?莫名其妙看不懂对吧。所以我们还是来看看实现生活中的例子。

模板方法模式是结构最简单的行为型设计模式,它是一种类行为模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供了一个称为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。它提供了具体的模板方法来定义算法结构,而具体步骤的实现可以在其子类中完成。

现在开始举例:柔性制造

生产,顾名思义,就是富有弹性和灵活性的生产方式,精益生产即是柔性生产精髓的表现。柔性生产建立在柔性制造的基础上,以市场为导向,按需生产,能够增强企业的灵活性和应变能力,提高生产效率,缩短生产周期,帮助企业适应多变的市场需求和激烈的市场竞争,具有强大的生命力。

“柔性”是 相对于“刚性”而言的,传统的“刚性”自动化生产线主要实现单一品种的大批量生产,而“柔性”生产线则更能够满足当今消费者个性化、多样化的需求。

一、柔性制造的基本特征

1、机器柔性:当要求生产一系列不同类型的产品时,机器随产品变化而加工不同零件的难易程度。

2、工艺柔性:系统能够根据加工对象的变化或原材料的变化而确定相应的工艺流程,其中一是工艺流程不变时自身适应产品或原材料变化的能力;二是制造系统内为适应产品或原材料变化而改变相应工艺的难易程度。

3、产品柔性:一是产品更新或完全转向后,系统能够非常经济和迅速地生产出新产品的能力;二是产品更新后,对老产品有用特性的集成能力和兼容能力。

4、维护柔性:系统能够采用多种方式查询、处理故障,保障生产正常进行。

5、生产能力柔性:当生产量改变时,系统也能经济地运行的能力。对于根据订货而组织生产的制造系统,这一点尤为重要。

6、扩展柔性:当生产需要的时候,可以容易地扩展系统结构,增加模块,构成一个更大系统的能力。

7、运行柔性:利用不同的机器、材料、工艺流程来生产一系列产品的能力和同样的产品,换用不同工序加工的能力。

总而言之,柔性生产的核心是柔性制造技术,而柔性制造技术是对各种不同形状加工对象实现程序化柔性制造加工的各种技术的总和。柔性制造技术是技术密集型的技术群,我们认为凡是侧重于柔性、适应于多品种、中小批量(包括单件产品)的加工技术都属于柔性制造技术。

二、柔性制造的基本功能

1、能够自动控制和管理零件的加工过程,包括制造质量的自动控制、故障的自动诊断和处理、制造信息的自动采集和处理。2、通过简单的软件系统变更,便能制造出某一零件族的多种零件。3、自动控制和管理物料(包括工件与刀具)的运输和存储过程。4、能解决多机床下零件的混流加工,且无需增加额外费用。5、具有优化的调度管理功能,无需过多的人工介入,能做到无人加工。

三、什么是柔性制造系统

根据我国国家军用标准,柔性制造系统是由数控加工设备、物料运储装置和计算机控制系统组成的自动化制造系统,它包括多个柔性制造单元,能根据制造任务或生产环境的变化迅速进行调整,适用于多品种、中小批量生产。简单来说,FMS是由若干数控设备、物料运储装置和计算机控制系统组成的,并且能够根据制造任务和生产品种变化而迅速进行调整的自动化制造系统。

目前常见的组成通常包括4台或更多台全自动数控机床(加工中心与车削中心等),由集中的控制系统及物料搬运系统连接起来,可在不停机的情况下实现多品种、中小批量的加工及管理。

四、柔性制造系统的优点

1、提高了设备利用率:通过计算机把每个零件安排了相应的加工机床,该机床空闲时就马上将零件送上加工,尽量使制造系统中的加工设备都得到利用。由于设备的利用率高,能以较少的设备达到传统生产线的产量,从而降低了设备的投资成本。

2、提高了生产的应变能力:当今的消费者的需求更加个性化和多样化,而柔性制造系统有其内在的灵活性,能适应由于市场需求变化和工程设计变更所出现的变动,进行多种产品的生产。而且能够在不明显打乱正常生产计划的情况下,插入备件和急件制造任务。

3、提高了生产效率:因为柔性制造更看重需求,其实属于按照需求生产的拉动型生产模式。不需要浪费大量时间等待之前的工序加工完成,从而缩短了生产制造的时间,提高了生产效率。除此之外,还能减少库存量,节约进行储存的仓库成本。

五、柔性制造系统的核心技术

1、计算机辅助设计

2、模糊控制技术

3、人工智能、专家系统及智能传感器技术

4、人工神经网络技术

5、综合控制系统

以上技术就不做介绍了,大家感兴趣的话可以自行查阅哦。

总结

柔性制造技术是实现未来工厂的新概念模式和新的发展趋势,是决定制造企业未来发展前途的具有战略意义的举措。届时,智能化机械与人之间将相互融合,柔性地全面协调从接受订货单至生产、销售这一企业生产经营的全部活动。所以生产一个产品,往往简化后就是:原料——生产——产品

这个步骤中,原料和产品的工序变化不大,但中间这个生产步骤区别就大了,为了满足柔性制造的要求,生产这个步骤差别会很大很大。

在软件开发中,某个方法的实现需要多个步骤(类似“柔性制造”),其中有些步骤是固定的(类似“原料”和“产品”),而有些步骤并不固定,存在可变性(类似“生产”)。为了提高代码的复用性和系统的灵活性,可以使用一种称之为模板方法模式的设计模式来对这类情况进行设计,在模板方法模式中,将实现功能的每一个步骤所对应的方法称为基本方法(例如“原料——生产——产品”),而调用这些基本方法同时定义基本方法的执行次序的方法称为模板方法(例如“柔性制造”)。在模板方法模式中,可以将相同的代码放在父类中,例如将模板方法“柔性制造”以及基本方法“原料”和“产品”的实现放在父类中,而对于基本方法“生产”,在父类中只做一个声明,将其具体实现放在不同的子类中,在一个子类中提供“第一种生产方法”的实现,而另一个子类提供“第二种生产方法”的实现。通过使用模板方法模式,一方面提高了代码的复用性,另一方面还可以利用面向对象的多态性,在运行时选择一种具体子类,实现完整的“柔性制造”方法,提高系统的灵活性和可扩展性。
 

模板方法模式包含如下两个角色: (1) AbstractClass(抽象类):在抽象类中定义了一系列基本操作(PrimitiveOperations),这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。  (2) ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。

在实现模板方法模式时,开发抽象类的软件设计师和开发具体子类的程序员之间可以进行协作。一个设计师负责给出一个算法的轮廓和框架,程序员则负责给出这个算法的各个逻辑步骤。实现这些具体逻辑步骤的方法即为基本方法,而将这些基本方法汇总起来的方法即为模板方法。下面介绍模板方法和基本方法:
 

1. 模板方法

 一个模板方法是定义在抽象类中的、把基本操作方法组合在一起形成一个总算法或一个总行为的方法。这个模板方法定义在抽象类中,并由子类不加以修改地完全继承下来。模板方法是一个具体方法,它给出了一个顶层逻辑框架,而逻辑的组成步骤在抽象类中可以是具体方法,也可以是抽象方法。由于模板方法是具体方法,因此模板方法模式中的抽象层只能是抽象类。

2. 基本方法

基本方法是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:

 (1) 抽象方法:一个抽象方法由抽象类声明、由其具体子类实现。在Java和C#语言里一个抽象方法以abstract关键字标识。

 (2) 具体方法:一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。

 (3) 钩子方法:一个钩子方法由一个抽象类或具体类声明并实现,而其子类可能会加以扩展。通常在父类中给出的实现是一个空实现(可使用virtual关键字将其定义为虚函数),并以该空实现作为方法的默认实现,当然钩子方法也可以提供一个非空的默认实现。

好了,这里会有点难度,请大家耐心看完。Hook(钩子)是一种特殊的消息处理机制,它可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理。所以说,我们可以在系统中自定义钩子,用来监视系统中特定事件的发生,完成特定功能,如屏幕取词,监视日志,截获键盘、鼠标输入等等。钩子来源于英文词hook。在Windows系统中一切皆消息,按键盘上的键,也是一个消息。Hook 的意思是钩住,也就是在消息过去之前,先把消息钩住,不让其传递,使用户可以优先处理。执行这种操作的函数也称为钩子函数。简单地讲,就是“要想从这过,留下买路钱”。即执行某操作之前,优先处理一下,再决定后面的执行走向。程序中需要监视的动作都可以调用,但运用的时候也要考虑资源问题。比如:激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;完成系统指令;来自系统消息队列中的移动鼠标,键盘事件;设置输入焦点事件;同步系统消息队列事件。

在模板方法模式中,钩子方法有两类:第一类钩子方法可以与一些具体步骤“挂钩”,以实现在不同条件下执行模板方法中的不同步骤,这类钩子方法的返回类型通常是boolean类型的,这类方法名一般为isXXX(),用于对某个条件进行判断,如果条件满足则执行某一步骤,否则将不执行,如下代码片段所示:
 

……
//模板方法
public void TemplateMethod(){
    Open();
    Display();
    //通过钩子方法来确定某步骤是否执行
    if (isPrint()) {
        Print();
     }
}
 
//钩子方法
public bool isPrint(){
    return true;
}
……

在代码中isPrint()方法即是钩子方法,它可以决定Print()方法是否执行,一般情况下,钩子方法的返回值为true,如果不希望某方法执行,可以在其子类中覆盖钩子方法,将其返回值改为false即可,这种类型的钩子方法可以控制方法的执行,对一个算法进行约束。

还有一类钩子方法就是实现体为空的具体方法,子类可以根据需要覆盖或者继承这些钩子方法,与抽象方法相比,这类钩子方法的好处在于子类如果没有覆盖父类中定义的钩子方法,编译可以正常通过,但是如果没有覆盖父类中声明的抽象方法,编译将报错。在模板方法模式中,抽象类的典型代码如下:

public abstract class AbstractClass{
    //模板方法
    public void TemplateMethod() {
        PrimitiveOperation1();
        PrimitiveOperation2();
        PrimitiveOperation3();
    }
 
    //基本方法—具体方法
    public void PrimitiveOperation1(){
         //实现代码
    }
 
    //基本方法—抽象方法
    public abstract void PrimitiveOperation2();    
 
    //基本方法—钩子方法
    public virtual void PrimitiveOperation3()   
    { }
}

在抽象类中,模板方法TemplateMethod()定义了算法的框架,在模板方法中调用基本方法以实现完整的算法,每一个基本方法如PrimitiveOperation1()、PrimitiveOperation2()等均实现了算法的一部分,对于所有子类都相同的基本方法可在父类提供具体实现,例如PrimitiveOperation1(),否则在父类声明为抽象方法或钩子方法,由不同的子类提供不同的实现,例如PrimitiveOperation2()和PrimitiveOperation3()。

可在抽象类的子类中提供抽象步骤的实现,也可覆盖父类中已经实现的具体方法,具体子类的典型代码如下:

public class ConcreteClass : AbstractClass{
    public void PrimitiveOperation2() {
        //实现代码
    }
 
    public void PrimitiveOperation3() {
        //实现代码
    }
}

在模板方法模式中,由于面向对象的多态性,子类对象在运行时将覆盖父类对象,子类中定义的方法也将覆盖父类中定义的方法,因此程序在运行时,具体子类的基本方法将覆盖父类中定义的基本方法,子类的钩子方法也将覆盖父类的钩子方法,从而可以通过在子类中实现的钩子方法对父类方法的执行进行约束,实现子类对父类行为的反向控制。

应用实例

一家制造企业财务系统为不同的柔性生产线开发一个金额计算功能,计算流程如下:根据用户类型的不同使用不同的利息计算公式计算利息, 系统显示利息。Account充当抽象类角色,CurrentAccount和SavingAccount充当具体子类角色。

  (1) Account:账户类,充当抽象类。

package designpatterns.templatemethod;

public abstract class Account{
    //基本方法——具体方法
    public bool validate(string account, string password) {
	    System.out.println("账号:", account);
        System.out println("密码:", password);
        if (account.Equals("员工1") && password.Equals("123456")){
			    return true;
		    }
		    else{
			    return false;
		    }
	    }
 
    //基本方法——抽象方法
    public abstract void calculateInterest();
 
    //基本方法——具体方法
    public void display() {
          Console.WriteLine("显示");
    }
 
    //模板方法
    public void Handle(string account, string password) {
          if (!validate(account,password)) {
                 System.out println("账户或密码错误");
			     return;
		   }
		   calculateInterest();
		   display();
	    }
    }
}

   (2) CurrentAccount:活期账户类,充当具体子类。

package designpatterns.templatemethod;
 
public class CurrentAccount extends Account {
        //覆盖父类的抽象基本方法
        public void calculateInterest() 
        {
		    System.out.println("按活期利率计算利息");
	    }
    }
}

   (3) SavingAccount:定期账户类,充当具体子类。

package designpatterns.templatemethod;
 
public class SavingAccount extends Account {
        //覆盖父类的抽象基本方法
        public void calculateInterest() 
        {
		    System.out.println("按定期利率计算利息");
	    }
    }
}

   (4) 配置文件config.xml,在配置文件中存储了具体子类的类名。

<?xml version="1.0"?>
<config>
   <className>designpatterns.templatemethod.CurrentAccount</className>
</config>

(5)XMLUtil:工具类。
 

package designpatterns. templatemethod;

import javax. xml. parsers.*
import org.3c.dom.*;
import java.io.;

public class XMLUtil {
  //该方法用于从XML配置文件中提取具体类的类名,并返回一个实例对象
    public static Object getBean(){
      try {
         //创建DOM文档对象
         DocumentBuilderFactory dFactory = DocumentBuilderFactory. newInstance();
         DocumentBuilder builder = dFactory. newDocumentBuilder();
         Document doc;
         doc = builder. parse(new File("src//designpatterns//templatemethod//config. xml"));
    
          //获取包含类名的文本结点
        NodeList nl = doc. getElementsByTagName("className");
        Node classNode= nl. item(0). getFirstChild();
        String cName = classNode. getNodeValue();

        //通过类名生成实例对象并将其返回
        Class c= Class, forName(cName);
        Object obj=c. newInstance();
        return obj;
     }
    catch(Exception e){
         e. printStackTrace();
         return null;
      }
   }
}

(6)客户端测试类

package designpatterns. templatemethod;
 
public class Client {
       public static void Main(String[] args){
            Account account;
            //读取配置文件,反射生成对象
            account = (Account)XMLUtil.getBean();
            account.Handle("员工1", "123456");
        }   
}

总结一下,在以下情况下可以考虑使用模板方法模式:

 (1) 对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。 (2) 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。(3) 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
 

各位小伙伴,这也是我的设计模式帖子《Windows环境下实现设计模式》的最后一期,以后不再写这个话题了,感觉好像设计模式的帖子没什么人爱看。也许是因为太难了,也许是因为别人写的相关帖子更好看。无论如何,这是《Windows环境下实现设计模式》的最后一期了。以后我写的编程帖子里如果有涉及到设计模式的,我肯定还会详细介绍的,希望对大家学习有帮助。

作者简介:荔园微风,1981年生,高级工程师,浙大工学硕士,软件工程项目主管,做过程序员、软件设计师、系统架构师,早期的Windows程序员,Visual Studio忠实用户,C/C++使用者,是一位在计算机界学习、拼搏、奋斗了25年的老将,经历了UNIX时代、桌面WIN32时代、Web应用时代、云计算时代、手机安卓时代、大数据时代、ICT时代、AI深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值