定义 模板方法设计模式的定义如下: 定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 钩子就是在整体流程的设计中,故意留下的供子类灵活变更的钥匙。 钩子是一种被声明在抽象类中的方法,但钩子只有空的或者默认方法实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。 但如果遇到适合的场景,使用这种设计模式也非常方便,因为可以控制整套逻辑的执行顺序和统一的输入、输出,而对于实现方,只需要关心自己的业务逻辑即可。 另外,模板模式也是为了解决子类通用方法,放到父类中优化设计。让每一个子类只做子类需要完成的内容,而不需要关心其他逻辑。再提取公用代码,行为由父类管理,扩展可变部分,也就非常有利于开发拓展和迭代了。 Copyright: 采用 知识共享署名4.0 国际许可协议进行许可 Links: https://lixj.fun/archives/设计模式-模板方法设计模式
模板方法模式是基于继承的代码复用的基本技术,模板方法模式的结构和用法也是面向对象设计的核心。 模板方法的本质:抽象封装流程,具体进行实现 模版方法模式需要开发抽象类和具体子类的设计师之间的协作。 一个设计师负责给出一个算法的轮廓和骨架 另一些设计师则负责给出这个算法的各个逻辑步骤。 代表这些具体逻辑步骤的方法称做基本方法(primitive method) 将这些基本方法总汇起来的方法叫做模版方法(template method),这个设计模式的名字就是从此而来。 多个子类有公有的方法,并且逻辑基本相同时; 重要,复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现; 重构时,模板方法模式 是一个经常使用的模式,把相同的代码抽取到父类,然后通过钩子函数约束其行为 最后,设计模式给出的是一种设计框架,而不是条条框框,你需要用的是他真正优秀的地方! 开发实例 ?
模板方法 使用基类定义整体步骤,即若干方法的调用过程,将一些可变的步骤由子类去重写。这样就可以利用多态在不改变操作的整体结构下定制一些特殊细节。 代码解释 可以联想在线电子邮件和普通邮递的区别。 on**()方法,目标方法在调用子类重写的方法时通常做了很多额外准备工作和后续工作。 dirtyOpaque) onDraw(canvas); ... } ViewGroup事件分发 ViewGroup在方法dispatchTouchEvent()中定义了事件分发机制的整体结构。 子类需要重写以下方法来定制事件处理过程: public boolean onInterceptTouchEvent(MotionEvent ev); public boolean onTouchEvent 模板方法强调抽象过程的不变性,某些细节的可变性。
2.算法的常用设计方法 实际应用的算法千变万化,种类繁多。设计一个好的算法需要设计者根据实际要解决的问题,充分发挥自己的分析和综合能力,经过认真构思、仔细设计和耐心调整。 在算法的设计过程中,最重要的是创新精神。经过数千年无数前人的创新,人类不近积累了大量精妙的算法,同时在算法的设计方法上也进行了深入的探讨,发现许多不同问题的解决算法,它们的设计思想有相似之处。 经过科学的总结,找到了一些行之有效的能够用于设计算法的一般方法。下面列举最常用的算法设计的方法。 2.3递归法 递归(Recursion)是设计和描述算法的一种有力的工具,由于它在复杂算法的描述中被经常采用,为此在进一步介绍其他算法设计方法之前先讨论它。 如迷宫问题和八皇后问题都可以采用回溯方法来设计求解算法。
什么是模版方法? 借助抽象类定义算法的骨架,再由具体子类实现算法的特定步骤。 这种设计模式让算法的整体结构得以固定,同时又能让不同的子类灵活地实现具体步骤; 简单来说就是使用抽象类,把要实现的功能框架写好,里面的具体实现细节设置为虚函数; 怎么理解抽象类的算法骨架? 首先我们要知道什么是抽象类,抽象类就是还有纯虚函数的类就叫做抽象类,抽象类是不可以实例化的,这也是抽象类作为模版的重要原因; 我们在抽象类中定义的纯虚函数,后面再继承的派生类中都是需要进行重写的,这算是模版方法的使用方法 ; Burn功能骨架 这里我以一个游戏中常见的角色类为例; #include<bits/stdc++.h> using namespace std; //模版方法--抽象类 class Factor ,骨架是一样的,但是里面的内容是不一样的,不同的对象可以从过重写骨架中的接口和方法,实现不同的效果,这就是多态的应用!!!
说明 模板方法是通过汇总 或排序基本方法而产生的结果集。 模板方法在一些开源框架中应用很多,它提供了一个抽象类,然后开源 框架写了一堆子类,在《XXX In Action》中就说明了,如果你需要扩展功能,可以继承了这个抽象类,然 后修改 protected 方法 父类调用子类的静态方法。 这三种都是父类直接调用子类的方法,好用不?好用!解决问题了吗?解决了!项目中允许使用不? 不允许! 其实这个问题可以换个角度去理解,在重写了父类部分方法后,再调用从父类继承的方法,产生 不同的结果(而这正是模板方法模式),这是不是也可以理解为父类调用了子类的方法呢? 你修改了子类, 影响了父类的结果,模板方法模式就是这样效果。 示例 // 别想了 这个设计过于简单 正常编码就能编写 别看啥例子了 要看再百度一下子
; 3、然后是具体的类,XXXDisplay继承自AbstractDisplay,并去重写父类方法等 通常在第2步时发现,虽然当前类为一个抽象类,但是里面却有部分的有方法体的方法(可能被final修时, 也可能没有被final修时),并且这些方法体内部调用了抽象方法。 具有这种特征的模式即为模板方法。 显而易见,抽象类中定义了模板方法,但又需要子类自己的逻辑去配合父类的模板方法才能完成最终的方法调用。 ||||||||||||| 正如示例代码所示: 1、父类(抽象类)定义了抽象方法和模板方法 2、子类实现抽象方法 3、在执行父类的模板方法的时候发现,具体的逻辑会根据具体的子类型来确定。 这就 实现了一个模板算法下的不同的实现内容 到此大家应该也对模板方法有了个大概的认识,下面我们来总结一下模板方法的重要特征(敲黑板): 1、关于模板方法Template Method的角色划分:抽象类和具象子类
菜鸟:大家伙儿常说的模板方法是什么? 码农:设计模式的经典名著中Design Patterns: Elements of Reusable Object-Oriented Software(《设计模式——可复用面向对象软件的基础》)提出的一种软件编码思想模式 菜鸟:这跟模板方法有什么关系? 码农:模板方法就是来解决这个问题的;将完成一件事情的稳定和变化独立开来,定义好一个操作的算法骨架(稳定),而将一些步骤延迟到具体场景中实现(变化);模板方法使得不同场景复用同一个算法框架,具体的场景重定义算法的某些特定步骤 / 上层应用逻辑程序代码class application : public library {public:application(){}virtual ~application(){}//重写父类方法
掌握8条方法设计规则,设计优雅健壮的Java方法一个良好的方法设计可以提高代码的可读性、可维护性和可扩展性,而糟糕的方法设计则可能导致代码难以理解和修改本文基于 Effective Java 方法章节总结 8条设计方法的规则,帮助开发者更好进行方法设计检查参数的有效性为了防止错误发生,方法中一般会对参数进行校验,比如ArrayList的构造和添加方法传入容量为负数会抛出非法参数异常IllegalArgumentExceptionpublic ,但是这样可能存在频繁创建对象的性能问题如果调用方是可信任的(不会修改逃逸的可变对象),那么也可以不进行保护性拷贝(在文档中说明)谨慎设计方法1.谨慎选择方法的名称见名知意2.不要过于追求提供便利的方法设计 ,它原本可能这样设计,接受一个布尔参数来决定是否需要立即执行发货操作immediateShipping 参数的含义不是非常直观,使用者需要查阅文档或者根据上下文理解true和false的具体含义 (入参、响应)解决设计方法时需要见名知意、避免参数过长、定义参数类型为接口而不是类、boolean类型考虑泛型,并且API中不要追求大量便利的方法,这种方法应该在工具类中重载编译时就能够确定,为了避免转换类型调用错重载方法
信号隔离技术 控制下电模块输出的基本方法是使用隔离单元将输出箝位到一个特定的、合法的值。 当使用高有效逻辑时,最常见的方法是将值箝位到“0”,与门电路功能实现了这一点。当使用低有效逻辑时,或门逻辑电路将输出停在逻辑“1”处。 然而,这种方法在电源门控网络上引入了多个驱动程序,需要仔细的排序以避免信号争用。即使上拉或下拉晶体管是相对较弱的器件,当总数量可能足够大时,从总线争用的过剩电流可能会导致问题。 在不同的设计中重用此设计时,必须在每种情况下再次执行此分析。 然而,在源处设置隔离确实对摆放位置和路由有一些限制。不同于电源门组中的其他门,隔离单元在断电期间必须保持供电。 这种方法允许在进程中重新启动协议,而不是在复位状态下启动协议。这个策略需要一个锁存的隔离单元,并非在所有库中都可用,因此应该仅在绝对必要时使用。
电源门控设计验证--RTL仿真 接下来我们考虑在RTL级验证电源门控电路的问题。这是一个挑战,因为硬件描述语言没有在RTL级别提供描述电源连接的机制。 图5-10显示了我们想要仿真的设计的电源连接。Verilog模块my_module (实例U1)有一个Header开关,用于控制模块中所有逻辑的电源。 上述设计的UPF描述可能如下所示: 如果在仿真时包含此UPF代码,则会发生以下情况: 当pwr_req拉低(请求断电)时,开关将关闭U1中的所有单元的电源。 在RTL中推断电源门控和保持行为 对于使用保留寄存器的设计,下一步是修改RTL以进行行为建模: •对保持初始化保持状态变量到“X”以在 SAVE 操作之前捕获无效的 RESTORE。
状态保持和恢复方法 接着上文继续 低功耗设计方法-电源门控设计(一) 低功耗设计方法-电源门控设计(二) 给定电源开关结构和隔离策略,可以对逻辑块进行电源门控。 有几种方法可以保存和恢复电源门控块的内部状态: 一种是基于读写寄存器的软件方法。 一种是基于扫描链在芯片外存储状态的方式。 一种是使用保留寄存器的方法。 从RTL设计的角度来看,当然存在挑战。最基本的挑战是在综合之前,扫描触发器不会被插入和连接起来—但有必要在综合之前在 RTL 级别对控制器进行编码和调试。 尽管存在这些挑战,但基于扫描的状态保留方法在某些情况下还是有用的。对于长期休眠,完全关闭整个子系统,特别是关闭外部电源可以显著减少泄漏。 一种方法是在RTL设计中添加一些条件代码,它只在模拟基于扫描的保留时才编译。这段代码模拟了移位寄存器的行为,可以包含在简单的测试序列中,以验证控制器是否正常工作,数据是否被正确地写入和从内存中读取。
状态保持和恢复方法 保留寄存器 在电源门控的同时提供状态保留的另一种方法是用保留寄存器替换标准寄存器。保留寄存器包含一个“影子”寄存器,它可以在关机期间保持寄存器状态并在通电时恢复它。 出于这个原因,大多数设计师设计在执行保存之前就停止了时钟。但是保存操作必须在断电前完成。 在电源恢复和电源门控状态消退之前,不能执行恢复。恢复操作必须在新值加载到主寄存器之前完成。 由于这个原因,大多数设计人员直到恢复操作完成后才重新启动时钟。 虽然电源门控控制器在设计上需要谨慎,但在实现过程中可以自动完成标准触发器的保持寄存器的实际替换。 浅状态是指直接控制设计逻辑的寄存器—即可以绘制为状态机图的设计部分。深度状态是指状态机使用的寄存器,但它包含大量的辅助数据,如内存、计数器和FIFOs。 基于扫描的保存和恢复方法很可能使用系统总线对数据进行交互。这个总线通常可以有等待状态,因此需要小心确保扫描保存/还原控制器能够支持等待状态而不丢失任何数据。
电源门控设计 给定电源开关结构、隔离策略和保持策略,我们现在可以设计控制掉电和上电排序的电源控制器。 电源控制顺序 从上面的讨论中,我们提取了以下对无保留寄存器的电源门控的要求。 以尽量减少电源门控区域的泄漏 确认隔离控制信号,使所有输出都处于安全状态 确认块复位,以便它在复位条件下上电 置位电源门控控制信号以关闭模块 恢复供电: 取消电源门控信号,以恢复电源模块 根据电流涌流管理方法和技术 确认保留状态保存条件(脉冲或边缘触发取决于技术) 确认对块中的非保留寄存器进行复位,以便它们在复位条件下启动 确认电源门控控制信号关闭模块 恢复供电和保留状态: 取消电源门控信号,以恢复电源模块 根据电流涌流管理方法和技术 最简单的方法是在控制器排序中建立一个固定的延迟,计数器可以添加足够的时钟周期来满足上电或关闭时间,然而在RTL中嵌入这些时间常数将使得RTL与特定开关结构的时序联系起来。 设计人员在设计电源控制器时需要仔细考虑这种情况。请记住,断电时间取决于半导体工艺和温度。
因此,在模板方法模式的类结构图中,只有继承关系。 核心设计要点: AbstractClass : 抽象类,定义并实现一个模板方法。 这个模板方法定义了算法的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类去实现 ConcreteClass : 实现实现父类所定义的一个或多个抽象方法。 模版方法优缺点 1.)优点 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。子类实现算法的某些细节,有助于算法的扩展。 2.)缺点 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。 3.)适用场景 在某些类的算法中,用了相同的方法,造成代码的重复。控制子类扩展,子类必须遵守算法规则。 策略模式 不同的骨架(多重if) 模版方法 相同的骨架 servlet 模版方法 doget dopost
总述 本章从前端RTL的角度描述电源门控的设计,该设计的关键部件示意图如图5-1所示。 电源门控的关键包括开关结构的设计和电源门控控制器的设计。我们还需要确定何时何地插入保留寄存器和隔离单元。 在使用这种设计方法的芯片中,在电源门控块上切换VSS可能是一个问题。 最后,设计师认为“关闭”意味着信号被拉回VSS。当电源(而不是接地)切换时,更容易思考所有的系统设计问题。 控制这种涌流的各种方法将在后面详细描述。一种代表性的方法是用链状结构将控制信号传递给开关。 打开开关结构的一个更积极的方法是按顺序使用几个通电控制信号。第一个控制信号可能打开一组微弱或“涓滴”开关,启动电源,但限制涌流。第二个控制信号可以打开主电源开关。 不管具体的控制方法是什么,在上电过程中,重要的是要等到开关结构完全上电后才能使电源门控块恢复正常运行。这个上电顺序的时间由电源控制器负责。
可测试性考虑 电源门控可测试性设计 RTL 设计要求设计人员确保复位的可控性以实现可测试性。所有派生或重新同步的复位(或预设)都从外部可控的主复位控制引脚复用。 由于背景泄漏可能很高,现代 IDDQ 测试方法通常比较多个测量值,有时跨越多个芯片,而不是设置单个阈值。 功能测试将是特定于设计的。扫描测试方法要求我们在扫描期间强制电源控制器输出的输出处于适当的状态—这样我们就可以避免在测试期间意外地上下切换电源网格。 促进这种控制的一种方法是将电源门控控制器封装在 IEEE 1500 封装器中。这种方法确保了电源门控控制器的完全可控性和可观察性,同时允许我们将控制器的输出保持在一个稳定的值。 一种方法是要求每个测量具有相对于其他测量指定的值,例如要求睡眠状态泄漏小于操作泄漏的 20%。
送出“奶茶”饮料; 4.2 错误推测法 4.2.1 定义 错误猜测法是测试经验丰富的人喜欢使用的一种测试用例设计方法。 一般这种方法是基于经验和直觉推测程序中可能发送的各种错误,有针对性地设计。 4.3 判定表 4.3.1定义: 设计测试用例时,分析和表达多输入条件下执行不同操作的黑盒测试方法。 注意: 该方法和因果图法相似。 这种试验设计法是从大量的试验点中挑选适量的具有代表性的点,利用已经造好的表格—正交表来安排试验并进行数据分析的方法。 选择正交表.png ③因素与水平 因素与水平.png ④确定 结果.png 正交表测试用例设计方法的特点是什么? 第五单元 测试用例设计方法(三)- 场景法 5.1 定义 通过模拟业务场景来对系统的功能点或业务流程的描述,从而提高测试效果的黑盒测试方法 5.2 ATM引入场景法 ATM流程图.png 5.3 原理图
,其中有些步骤是固定的,有些步骤是不固定的 问题改进 使用模板方法模式来设计,一方面可以提高了代码的复用性,另一方面还可以利用面向对象的多态性,在运行时选择一种具体子类,实现完整的烹饪方法,提高系统的灵活性和可扩展性 其基本思想是抽象类提供一个称之为“模板”的方法,在这个方法中调用一些复杂流程的实现步骤,在这个方法中调用的基本步骤由其子类来重载,从而使得相同的算法框架可以有不同的执行结果 模板方法模式类图 模板方法模式类图 同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法 具体方法:重载父类中的抽象方法并加以实现 钩子方法:由一个抽象类声明,子类实现,其子类可能会加以扩展,通常在父类中会给出一个空实现 优点 在父类中声明一个基本方法,由子类实现,在子类实现时并不会改变算法中步骤的执行顺序 代码复用性强 不同子类可以提供基本方法的不同实现,跟换子类很方便,符合单一职责原则和开闭原则 缺点 需要为每个基本方法的不同实现提供一个子类,如父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大
模板方法 模板方法模式在一个方法中定义了一个算法骨架,并且 final 修饰防止子类重写。方法中包含一些抽象方法,也就是一些步骤延迟到字类实现。 模式实现 在实现模板方法模式时,开发抽象类的软件设计师和开发具体子类的软件设计师之间可以进行协作。一个设计师负责给出一个算法的轮廓和框架,另一些设 计师则负责给出这个算法的各个逻辑步骤。 实现这些具体逻辑步骤的方法即为基本方法,而将这些基本方法汇总起来的方法即为模板方法,模板方法模式的 名字也因此而来。 基本方法 基本方法是实现算法各个步骤的方法,是模板方法的组成部分。 这时候我们就可以使用模板方法设计模式定义制作骨架,然后部分细节留给子类实现。 代码实现 首先我们先抽象一个制作饮料的模板,定义算法逻辑 AbstractBeverage。