重构了XmlDownloader类

用了建造者模式。

在公交车上考虑了两天,在脑子里大概画了个雏形,然后今晚解决了一些细节上的问题。

不废话,发代码:

  1 package com.mlxy.xml;
  2 
  3 import java.io.BufferedReader;
  4 import java.io.BufferedWriter;
  5 import java.io.File;
  6 import java.io.FileOutputStream;
  7 import java.io.InputStream;
  8 import java.io.InputStreamReader;
  9 import java.io.OutputStreamWriter;
 10 import java.net.MalformedURLException;
 11 import java.net.URL;
 12 
 13 import android.content.Context;
 14 import android.os.Environment;
 15 
 16 import com.mlxy.util.CharacterProcesser;
 17 
 18 /**
 19  * Xml文件下载器,重构完成。
 20  * 
 21  * @author mlxy
 22  * @version 1.1
 23  * */
 24 public class XmlDownloader {
 25     private Context parent;
 26     
 27     private String cityName = "南昌";
 28     private String city = CharacterProcesser.encodeByGB2312(cityName);
 29     private String password = "DJOYnieT8234jlsK";
 30     private int day = 0;
 31     private String link = "http://php.weather.sina.com.cn/xml.php?city=" + city
 32             + "&password=" + password + "&day=" + day;
 33     
 34     /** 私有构造方法,避免被外部实例化。*/
 35     private XmlDownloader() {
 36     }
 37     
 38     /** 根据给定的链接下载对应的xml文件。
 39      * 
 40      * @param link API的链接,需要标明网络协议。*/
 41     private void downloadXml(String link) {
 42         // 用链接字符串new出URL对象
 43         URL url = null;
 44         try {
 45             url = new URL(link);
 46         } catch (MalformedURLException e) {
 47             e.printStackTrace();
 48         }
 49 
 50         // 获取外部存储路径并创建文件对象。
 51         File externalDirectory = Environment.getExternalStorageDirectory();
 52         String fileName = "xml_resource.xml";
 53         File file = new File(externalDirectory, fileName);
 54 
 55         // 写文件。
 56         
 57         // 初始化io流。
 58         InputStream in = null;
 59         BufferedReader reader = null;
 60         FileOutputStream out = null;
 61         BufferedWriter writer = null;
 62         
 63         try {
 64             
 65             // 建立连接并给io流赋值。
 66             in = (InputStream) url.getContent();
 67             reader = new BufferedReader(new InputStreamReader(in, "iso-8859-1"));
 68             out = this.parent.openFileOutput(file.getName(), Context.MODE_PRIVATE);
 69             writer = new BufferedWriter(new OutputStreamWriter(out, "iso-8859-1"));
 70             
 71             // 读一行写一行,然后另起一行。
 72             String line = null;
 73             while ((line = reader.readLine()) != null) {
 74                 writer.write(line);
 75                 writer.newLine();
 76             }
 77             
 78         } catch (Exception e) {
 79             e.printStackTrace();
 80         } finally {
 81             try {
 82                 // 释放资源
 83                 writer.flush();
 84                 writer.close();
 85                 out.close();
 86                 reader.close();
 87                 in.close();
 88             } catch (Exception e2) {
 89                 e2.printStackTrace();
 90             }
 91         }
 92     }
 93     
 94     private void setParent(Context parent) {
 95         this.parent = parent;
 96     }
 97     
 98     private void setCity(String cityName) {
 99         this.cityName = cityName;
100     }
101     
102     private void setPassword(String password) {
103         this.password = password;
104     }
105     
106     private void setDay(int day) {
107         this.day = day;
108     }
109     
110     private String getLink() {
111         return this.link;
112     }
113     
114     public static class Builder {
115         /** 储存好的一个实例,留待建造完毕后返回。*/
116         private XmlDownloader instance = new XmlDownloader();
117         
118         /** 构造函数,需要输入启动此构造器的上下文视图作为参数。*/
119         public Builder(Context parent) {
120             instance.setParent(parent);
121         }
122         
123         /** 设置城市名。</br>
124          * 默认值为<b>南昌</b>。
125          * 
126          * @param cityName 城市名
127          * @return 构造器本身
128          */
129         public Builder setCity(String cityName) {
130             instance.setCity(cityName);
131             return this;
132         }
133         
134         /** 设置密码。</br>
135          * 默认值为<b>DJOYnieT8234jlsK</b>。
136          * 
137          * @param password API密码
138          * @return 构造器本身
139          */
140         public Builder setPassword(String password) {
141             instance.setPassword(password);
142             return this;
143         }
144         
145         /** 设置日期。</br>
146          * 默认值为<b>0</b>,也即是<b>今天</b>。</br>
147          * 以此类推。
148          * 
149          * @param day 日子,0为当天,范围在0-4
150          * @return 构造器本身
151          */
152         public Builder setDay(int day) {
153             instance.setDay(day);
154             return this;
155         }
156         
157         /** 用已经设置好的或默认的参数下载XML文件。*/
158         public void download() {
159             String link = instance.getLink();
160             instance.downloadXml(link);
161         }
162     }
163 }
需要结合前面几篇博文看

场景类则这么调用:

 构建Xml下载器并下载Xml文件。
new XmlDownloader.Builder(MainActivity.this)
        .setCity("南昌")
        .setPassword("DJOYnieT8234jlsK")
        .setDay(0)
        .download();

具体实现方式参考了安卓的Toast和Dialog等几个类。

纠结了一天要不要给建造者提供默认值,就是说在用户没有自己设定参数的情况下是直接返回null还是用默认值来处理。

白天一直想着,不能惯用户的毛病。

然后到了晚上,我一想,用户不就是我么,除了我谁还用我写的这个类,就果断用了默认值。

另外,因为XmlDownloader这个类是不需要实例的,所以:

  1. 把无参构造函数限制成了私有的,这样别人就没法访问构造函数,也就没法实例化它。

  2. 去掉了几乎所有getter方法,同时把所有方法和属性定为私有的,因为不会存在任何XmlDownloader对象,也就没有必要对外开放任何接口。

  2.3.3 求不提反射。

  3. 要记得给Builder类加上static关键字,因为我们需要通过外部类来直接访问它,如果忘了的话,就会出现这样的一个错误:

No enclosing instance of type XmlDownloader is accessible. Must qualify the allocation with an enclosing instance of type XmlDownloader (e.g. x.new A() where x is an instance of XmlDownloader).

总的来说还是挺好用的,而且也不难,最关键的是

优雅!

用了设计模式之后我整个人都升华了你知道吗

原文地址:https://www.cnblogs.com/chihane/p/3629818.html