软g开发过E中Q唯一不变的就是变化。这是一句老生常谈Q也是说Y件开发中永恒的主题就是变化。当你把代码都写好了(jin)Q测试也完成?jin),准备交付的时候客户忽然要求你在指定时间做出变化,q种情况在外包行业中很常见;而对一些银行金融项目,边调研边开发边试屡见不鲜Q对于一些Web目Q从来就只有永远的Beta版,Ҏ(gu)改去的事更是家常侉K。对此,E序员(sh)定要求清晰的认识Q抱怨只能是嘴上痛快Q不解决实际问题。真要解军_际问题,非要动一番脑{不可,如果合理使用?jin)设计模式,反射或是Spring的IoCQ便能变?sh)改噩梦Zơ有的智慧之旅?/p>
首先我们看原始要求:(x)客户要求一扚w员名单存入到CSV和XML两种文g中去Q以后还有可能增加别的文件格式,比如PDFQXLS{,虽然q是下一期的内容Q但q一期应该考虑到变化,客户要求扩展性一定要好?/p>
没问题,有了(jin)设计模式响应变化不难。这时我们可以用到模板方法模式:(x)
定义一个操作中的算法的骨架Q而将一些步骤gq到子类?/strong>?/p>
先请看骨架抽象类Q?/p>
- public abstract class FileMaker {
-
-
-
- private List<Employee> employees;
-
-
-
-
-
-
-
- public final void makeFile(List<Employee> employees,String fileName){
- setEmployees(employees);
- makeFile(fileName);
- }
-
-
很好Q固定的函数和步骤都在抽象基cM写定?jin),再看两个具体实现c,它们要实现的是makeFile函数而已?/p>
- public class CSVFileMaker extends FileMaker{
- protected void makeFile(String fileName){
- try {
- BufferedWriter out = new BufferedWriter(new FileWriter(fileName));
-
- for(Employee emp:getEmployees()){
- String line="";
- line+=emp.getName()+",";
- line+=(emp.isMale()?"?:"?)+",";
- line+=emp.getAge()+",";
-
- out.write(line+"\r\n");
- }
-
- out.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- public class XMLFileMaker extends FileMaker{
- protected void makeFile(String fileName){
- try {
- Document document = DocumentHelper.createDocument();
- Element root = document.addElement("employees");
-
- for(Employee emp:getEmployees()){
- Element empElm=root.addElement("employee");
-
- Element nameElm=empElm.addElement("name");
- nameElm.setText(emp.getName());
-
- Element sexElm=empElm.addElement("sex");
- sexElm.setText(emp.isMale()?"?:"?);
-
- Element ageElm=empElm.addElement("age");
- ageElm.setText(String.valueOf(emp.getAge()));
- }
-
- OutputFormat format = OutputFormat.createPrettyPrint();
- format.setEncoding("GBK");
- XMLWriter writer = new XMLWriter(new FileWriter(fileName),format);
-
- writer.write(document);
- writer.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
q样昨完以后感觉很好Q因为我们成功的把变化和不变分离开来,不变的部分放在了(jin)抽象基类中,而容易变化的部分攑֜?jin)两个具体的子类中,q样如果再增加一U新文g格式Q从抽象基类再扩展出一个子cd可。很好,q样׃怕变化了(jin)。客户对此也没有异议?/p>
调用CZ如下Q?/p>
- List<Employee> emps=new ArrayList<Employee>();
- emps.add(new Employee("Andy",true,21));
- emps.add(new Employee("Bill",false,23));
- emps.add(new Employee("Cindy",true,25));
- emps.add(new Employee("Douglas",false,28));
-
- FileMaker fileMaker=new CSVFileMaker();
- fileMaker.makeFile(emps, "1.csv");
-
- fileMaker=new XMLFileMaker();
- fileMaker.makeFile(emps, "2.xml");
客户看到?jin)我们的调用的例子,觉得应该更灵zM些,他说存成各种不同的文件是通过点击按钮来实现的Q如果每个按钮的事g处理函数都要生成具体子类岂不是太L?jin)吗Q这样做每个文g下蝲按钮的事件处理代码不是都不一P
有点道理Q如今理解到q一层的客户实在是不多见?jin)。不q很Ҏ(gu)满他的需求,我们可以引入反射的方法:(x)
- public static void main(String[] args) {
- List<Employee> emps=new ArrayList<Employee>();
- emps.add(new Employee("Andy",true,21));
- emps.add(new Employee("Bill",false,23));
- emps.add(new Employee("Cindy",true,25));
- emps.add(new Employee("Douglas",false,28));
-
- callByReflect("csv",emps,"1.csv");
- callByReflect("xml",emps,"2.xml");
- }
-
- public static void callByReflect(String type,List<Employee> emps,String fileName){
- try{
- Class cls=Class.forName("com.heyang."+type.toUpperCase()+"FileMaker");
- FileMaker fileMaker=(FileMaker)cls.newInstance();
- fileMaker.makeFile(emps, fileName);
- }
- catch(Exception ex){
- ex.printStackTrace();
- }
- }
因ؓ(f)按钮上的文字和类名是有关的,如下载CSV的按钮上有CSV的文字,q可以通过正则表达式取道,再组合一下不是cd?jin)吗Q?/span>csv到com.heyang.CSVFileMaker,xml到com.heyang.XMLFileMakerQ其实变化就是三个字母而已。如果增加按钮,取出按钮中的三个字母再调用callByReflect函数卛_Q这个过E简直可以固化?/span>
客户看到反射Ҏ(gu)以后很是满意Q没有意见了(jin)。待客户走后Q项目经理把你拉C边,_(d)(x)
“你刚才的Ҏ(gu)不错Q确实很强,但看得懂反射q能灉|掌握的h水^要够一q经验才行,l护的活让一q经验的人去q太可惜?jin),最好改改,最好达到让新手也能掌握q修改的E度?#8221;?/span>
没办法,领导L领导的考虑Q他q么说也很合理,成本问题我可以不考虑Q但如果把程序搞得复杂貌似NBQ能让一些学Z_Z生云山雾|的感觉Q有时还能被人尊UC?#8220;大侠”Q但谁也不比谁傻多少Q这声大侠不是白叫的Q但是出?jin)问题或是有了(jin)变化别是要找你Q到头来q是l自己添乱,q些都是义务力_Q何苦来呢?q是应该改得Ҏ(gu)些,让大安能修改,我可不愿意半夜三更被人叫h问问题?/span>
用Spring的IoC可以解决问题,写一个新cdƈ配置到XML文g中对新手来说问题?sh)大Q这下可以让领导攑ֿ(j)?jin),自己更攑ֿ?j)?jin)?/span>
IoCҎ(gu)代码如下Q?/span>
- public class Main {
- public static void main(String[] args) {
- List<Employee> emps=new ArrayList<Employee>();
- emps.add(new Employee("Andy",true,21));
- emps.add(new Employee("Bill",false,23));
- emps.add(new Employee("Cindy",true,25));
- emps.add(new Employee("Douglas",false,28));
-
- callByIoc("csv",emps,"1.csv");
- callByIoc("xml",emps,"2.xml");
- }
-
- public static void callByIoc(String type,List<Employee> emps,String fileName){
- try{
- ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");
- FileMaker fileMaker=(FileMaker)ctx.getBean(type);
- fileMaker.makeFile(emps, fileName);
- }
- catch(Exception ex){
- ex.printStackTrace();
- }
- }
- }
Bean。xml文g内容很简单吧Q?/span>
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- <bean id="csv" class="com.heyang.CSVFileMaker"/>
- <bean id="xml" class="com.heyang.XMLFileMaker"/>
- </beans>
好了(jin)。到q里问题彻底结束了(jin)Q终于满了(jin)客户和上U的要求Q可以回家睡个好觉了(jin)Q不用担?j)别人打搅?jin)?/span>
态度改变?sh)切,变化来了(jin)人L要多做一些,?j)理当然是不愿意的,但抱怨或是消极抵刉不是解决问题?sh)道Q如果把它看做一个挑(xi)战的契机Q凡事多思考一些,不但能解决问题,自己也会(x)有所提高Q这是U极的态度带来的好处?/span>

]]>