public @interface TODO{} |
public @interface TODO{ String priority(); } |
@TODO( priority="high" ) public void calculate(){ //body omission } |
@TODO("high") |
public @interface TODO{ String priority(); String owner(); boolean testable() default true; } |
@TODO(priority="high",owner="Catherine" ) public void calculate(){ //body omission } |
@MarkerAnnotation |
@SingleValueAnnotation("some value") |
@MultipleValueAnnotation( key1=value1, key2=value2, key3=value3, ) |
public abstract class BaseClass{ //模板方法的基类 public void doWork(){ doPartI(); //先调用doPartI()方法 doPartII();//之后调用doPartII()方法 } public abstract void doPartI(); public void doPartII(){} } public class SubClass extend BaseClass{ public void doPartI(){}; @Override public void doPortII(){//拼写错误,产生编译错误 System.out.println("override the method of superclass"); } } |
@Target({ElementType.METHOD}) public @interface TODO { int priority() default 0; } |
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface TODO { int priority() default 0; } |
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface TOFORMATE { } |
public class MyCalculator { boolean isReady; @TOFORMATE double concurrency; @TOFORMATE Date debitDate; public MyCalculator() { super(); } @TODO public void calculateRate(){ System.out.println("Calculating..."); } } |
public class TestCalculator { public static void main(String[] args) { MyCalculator cal = new MyCalculator(); cal.calculateRate(); try { Class c = cal.getClass(); Method[] methods = c.getDeclaredMethods(); for (Method m: methods) { // 判断这个方法有没有使用TODO if (m.isAnnotationPresent(TODO.class)) System.out.println("Method "+m.getName()+": the TODO is present"); } Field[] fields = c.getDeclaredFields(); for (Field f : fields) { // 判断这个域有没有使用TOFORMATE if (f.isAnnotationPresent(TOFORMATE.class)) System.out.println("Field "+f.getName()+": the TOFORMATE is present"); } } catch (Exception exc) { exc.printStackTrace(); } } } |
在这里我们定义了一个Exporter抽象类,我们可以通过继承Exporter类,重写其visit方法来实现不同格式的文件输出。图11种给出visit方法的实现是一个简单的例子。如果要实现输出成XML格式的,可以定义Exporter子类:XMLExporter。如果希望输出成文本的可以定义TXTExporter。但是这样做不够灵活的地方在于,如果Employee加入其他的域变量,那么相应的visitor类也需要进行修改。这就违反了面向对象Open for Extension, close for Modification的原则。
使用注释替代Vistor模式
使用注释(Annotation),也可以完成数据输出的功能。首先定义一个新的注释类型:@Exportable。然后定义一个抽象的解释器ExportableGenerator,将Employee 对象传入解释器。在解释器中,查找哪些域使用了Exportable这个注释(Annotation),将这些域(Field)按照一定格式输出。图12给出了Exportable注释的定义。
清单16注释Exportable的定义
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface Exportable {} |
public abstract class Employee { public abstract String getName(); public abstract String getEmpNo(); public Employee() { super(); } } |
public class Regular extends Employee{ @Exportable String name; @Exportable String address; @Exportable String title; @Exportable String phone; @Exportable String location; @Exportable Date onboardDate; @Exportable ArrayList<Employee> team; String empNo; public Regular(String name, String address, String title, String phone, String location, Date date) { super(); this.name = name; this.address = address; this.title = title; this.phone = phone; this.location = location; onboardDate = date; team = new ArrayList<Employee>(); } public void addMemeber(Employee e){ team.add(e); } @Override public String getName() { // TODO Auto-generated method stub return name; } } |
public class Vendor extends Employee { @Exportable String name; @Exportable String company; @Exportable String team; @Exportable String workingHours; String empNo; public Vendor(String name, String company, String team, String hours) { super(); this.name = name; this.company = company; this.team = team; workingHours = hours; } } |
public class Contractor extends Employee{ @Exportable String name; @Exportable String company; @Exportable String contractDuration; String empNo; public Contractor(String name, String company) { super(); // TODO Auto-generated constructor stub this.name = name; this.company = company; contractDuration ="1"; } } |
public class Contractor extends Employee{ @Exportable String name; @Exportable String company; @Exportable String contractDuration; String empNo; public Contractor(String name, String company) { super(); this.name = name; this.company = company; contractDuration ="1"; } } |
public class TestExportable { public TestExportable() { super(); } public static void main(String[] args) { Regular em=new Regular("Catherine","IBM","Software Engineer","82888288","BJ", new Date()); Employee vn1=new Vendor("Steve","IBM","PVC","8"); Employee vn2=new Vendor("Steve","IBM","PVC","8"); Employee ct=new Contractor("Joe","IBM"); Employee sup=new Supplemental("Linda","IBM","8"); em.addMemeber(vn1); em.addMemeber(vn2); em.addMemeber(ct); em.addMemeber(sup); PrintWriter ps; try { ps = new PrintWriter(new FileOutputStream(new File("C://test.output"),true)); ExportableGenerator eg=new TXTExportableGenerator(ps); eg.genDoc(em,0); eg.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } } } |
public abstract class ExportableGenerator { PrintWriter out = null; public ExportableGenerator(PrintWriter out) { super(); this.out = out; } public void genDoc(Employee e, int tagNum) { Class employee = e.getClass(); Field[] fields = employee.getDeclaredFields(); outputFieldHeader(out,e); for (Field f : fields) { if (f.isAnnotationPresent(Exportable.class)) { if (f.getType() != ArrayList.class) { for(int i=0; i<tagNum;i++){ out.print("***"); } outputSimpleField(out, f, e); }else{ try { ArrayList team=(ArrayList)f.get(e); out.println("-----------------------------"); for(int i=0;i <team.size();i++){ Employee member=(Employee)team.get(i); genDoc(member,tagNum+1); out.println("-----------------------------"); } } catch (IllegalArgumentException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { e1.printStackTrace(); } } } } outputFieldFooter(out,e); } public void flush(){ out.flush(); out.close(); } protected String value(Field f, Object obj) { Class type = f.getType(); try { if (type == String.class) return (String) f.get(obj); if (type == Date.class) { return DateFormat.getDateInstance().format((Date)f.get(obj)); } } catch (IllegalArgumentException e) { e.printStackTrace(); return f.getName(); } catch (IllegalAccessException e) { e.printStackTrace(); return f.getName(); } return f.getName(); } protected abstract void outputSimpleField(PrintWriter out, Field f,Object obj); protected abstract void outputFieldHeader(PrintWriter out,Object e); protected abstract void outputFieldFooter(PrintWriter out,Object e); |
public class TXTExportableGenerator extends ExportableGenerator { public TXTExportableGenerator(PrintWriter out) { super(out); } @Override protected void outputSimpleField(PrintWriter out, Field f,Object obj) { out.print(f.getName()); out.print("="); out.print(value(f,obj)); out.print(";"); out.println(); } @Override protected void outputFieldHeader(PrintWriter out,Object e) {} @Override protected void outputFieldFooter(PrintWriter out,Object e) { //out.println(e.getClass().getName()+":"); } } |