1.
外观模式定义:
为子系统中的一组接口提供一个一致的的界面,Façade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
Façade类的形式:
Façade接口的形式:
Façade可以和单例模式,抽象工厂模式组合使用。
1. 适配器模式:
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
对象适配器类图:
双向适配器类图:
类适配器类图:
适配器通过转换调用已有的实现,从而能把已有的实现匹配成需要的接口,使之能满足客户端的需要。
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
生成器类图:
生成器模式和模板方法模式:
模板方法模式这要是用来定义算法的骨架,把算法中的某些步骤延迟到子类中实现。
生成器模式Director用来定义整体的构建算法(很像是模板方法里的抽象类,定义了各个部件组成顺序或算法结构),把算法中某些涉及到具体部件对象的创建和装配的功能,委托给具体的Builder来实现。
虽然生成器不是延迟到子类,是委托给Builder,但那只是具体实现方式上的差别,从实质上看两个模式很类似,都是定义一个固定的算法骨架,然后把算法中的某些具体步骤交给其他类来完成,都能实现整体算法步骤和某些具体步骤实现的分离。
区别:
首先是模式的目的,生成器模式是用来构建复杂对象的,而模板方法是用来定义算法骨架,尤其是一些复杂的业务功能的处理算法的骨架;
其次是模式的实现,生成器模式是采用委托的方法,而模板方法采用的是继承的方式,另外从使用的复杂度上,生成器模式需要组合Director和Builder对象,然后才能开始构建,要等构建完后才能获得最终的对象,而模板方法就没有这么麻烦,之间使用子类对象即可。
1. 模板模式:
定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
类图:
组装XML例子:
可以看到抽象类里会定义一个buliderXML方法,该方法定义构建对象的步骤与顺序。
XMlBulider继承了抽象类实现对象的组成各个部件实现。
为什么用抽象类而不用接口呢?
通常在“既要约束子类的行为,又要为子类提供公共功能”的时候使用抽象类。
按照这个原则使用抽象类。
1. Java回调和模板方法
还是组装XMl例子先看看类图
这里可以看到Xmlbulider类并没有实现callbackBuilder接口,并且,Xmlbulider也不是抽象类。
callbackBuilder接口中必须把所有可以被扩展的方法都要定义出来。
然后可以看到Xmlbulider类中的模板方法buliderXML传入回调接口。
在模板方法实现中,除了在模板中固定的实现外,所有可以被扩展的方法,都应该通过回调接口进行调用。
再看看client端实现代码:
public class client { public static void main(String[] args) { ExportHenderModel ehm=new ExportHenderModel(); ehm.setDeptId("001"); ehm.setExportdate("2013-11-8"); Map<String, Collection<ExportDataModel>> mapdata=new HashMap<String, Collection<ExportDataModel>>(); List<ExportDataModel> ilist=new ArrayList<ExportDataModel>(); ExportDataModel edm=new ExportDataModel(); edm.setProudctId("0011"); edm.setAmount(11); edm.setPrice(22); ilist.add(edm); mapdata.put("liwenjun", ilist); ExportFooterModel efm=new ExportFooterModel(); efm.setExportUser("liwenjun"); Xmlbulider xmlbulider=new Xmlbulider(); String xml= xmlbulider.buliderXML(ehm, mapdata, efm, new callbackBuilder(){ @Override public void builerHender(ExportHenderModel ehm,StringBuffer buffer) { // TODO Auto-generated method stub buffer.append(" <Hender>\n"); buffer.append(" <DeptId>" +ehm.getDeptId()+"</DeptId>\n"); buffer.append(" <Exportdate>" +ehm.getExportdate()+"</Exportdate>\n"); buffer.append(" </Hender>\n"); } @Override public void builerBody( Map<String, Collection<ExportDataModel>> mapdata,StringBuffer buffer) { // TODO Auto-generated method stub buffer.append(" <Body>\n"); for(String talname:mapdata.keySet()){ buffer.append( " <Datas TableName=\""+talname+"\">\n"); for(ExportDataModel edm:mapdata.get(talname)){ buffer.append(" <Data>\n"); buffer.append(" <ProudctId>" +edm.getProudctId()+"</ProudctId>\n"); buffer.append(" <Price>" +edm.getPrice()+"</Price>\n"); buffer.append(" <Amount>" +edm.getAmount()+"</Amount>\n"); buffer.append(" </Data>\n"); } buffer.append(" </Datas>\n"); } buffer.append(" </Body>\n"); } @Override public void builderFooter(ExportFooterModel efm,StringBuffer buffer) { // TODO Auto-generated method stub buffer.append(" <Footer>\n"); buffer.append(" <ExportUser>" +efm.getExportUser()+"</ExportUser>\n"); buffer.append(" </Footer>\n"); buffer.append(" </Report>\n"); } }); System.out.print(xml); } }
总结一下两种模板方法的实现方式:
使用继承方式,抽象方法和具体的关系是在编译期间静态决定的,是类级的关系。
使用java回调,这个关系是在运行期间动态决定的,是对象级的关系。
使用回调机制会更灵活,因为java是单继承的。
而使用回调,是基于接口的。
继承方式会更简单一些,因为父类提供了实现的方法,子类如果不想扩展,那就不用管。
如果使用回调机制,回调的接口需要把所有可能被扩展的方法都定义进去,这就导致实现的时候,不管你要不要扩展,都要实现这个方法。