在你的程序中應用一些設計模式讓你的代碼組織更有條理。懂得設計模式讓你更容易看懂一些優秀的源碼。本文逐步摸索各種設計模式。
1、對象的適配器模式
2、工廠方法模式
下面URL作爲工廠類,URLConnection作爲抽象產品,具體產品爲HttpURLConnectionImpl。
URL url = new URL("http://qinuli.com");
//HttpURLConnectionImpl
//抽象類,Factory Method Pattern
URLConnection urlConnection = url.openConnection();
Log.d(TAG, Thread.currentThread().getName()+"|"+urlConnection.getClass().getSimpleName());
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(urlConnection.getInputStream()));
Log.d(TAG, "before read");
String str;
while((str=bufferedReader.readLine())!=null){
Log.i(TAG, str);
}
斷網情況下,getInputStream()會報如下異常
3、觀察者模式
觀察者是一種很常見的設計模式,在Android中經常用到。比如SharedPreferences.registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener),
ContextWrapper.registerReceiver(BroadcastReceiver, IntentFilter)等。
MyApplication.java
public class MyApplication extends Application {
private static MyApplication me;
private DataCenter mDataCenter;
public MyApplication(){
super();
me = this;
}
public static MyApplication getInstance(){
return me;
}
@Override
public void onCreate() {
super.onCreate();
mDataCenter = new DataCenter();
}
public DataCenter getDataCenter(){
return mDataCenter;
}
}
MainActivity.javapublic class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private ChildView mChildView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup viewGroup = new FrameLayout(this);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
viewGroup.setLayoutParams(layoutParams);//ignored
LayoutInflater.from(this).inflate(R.layout.activity_main, viewGroup);
setContentView(viewGroup, layoutParams);
mChildView = (ChildView) findViewById(R.id.view);
MyApplication.getInstance().getDataCenter().addObserver(mChildView);
}
@Override
protected void onDestroy() {
super.onDestroy();
MyApplication.getInstance().getDataCenter().deleteObserver(mChildView);
}
public void onClick(View v){
switch(v.getId()){
case R.id.btn:
EditText editText = (EditText) findViewById(R.id.edit);
MyApplication.getInstance().getDataCenter().changeData(editText.getText().toString());
}
}
}
activity_main.xml<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical">
<EditText
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="ironman"/>
<com.qinuli.commontemplate.ChildView
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
ParentView.javapublic abstract class ParentView extends View {
private static final String TAG = ParentView.class.getSimpleName();
GestureDetector mGestureDetector;
public ParentView(Context context){
//單參供代碼中實例化用
//多參供xml文件用,2參調3參,3參調4參
super(context);
}
public ParentView(Context context, AttributeSet attrs){
super(context, attrs);
init();
}
private void init(){
mGestureDetector = new GestureDetector(getContext(), new MySimpleOnGestureListener());
}
/**
* 可共享外部類的屬性方法
* 避免單繼承的侷限
*/
public class MySimpleOnGestureListener extends SimpleOnGestureListener{
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.i(TAG, "onDoubleTap");
return true;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
/**
* 靜態方法依然可被繼承、覆寫
*/
public static void show(){
Log.d(TAG, "show");
}
}
ChildView.javapublic class ChildView extends ParentView implements Observer{
private static final String TAG = ChildView.class.getSimpleName();
private Paint mPaint;
private DisplayMetrics dm;
public ChildView(Context context){
super(context);
}
public ChildView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init(){
dm = getContext().getResources().getDisplayMetrics();
mPaint = new Paint();mPaint.setTextSize(20f * dm.density);
this.data = MyApplication.getInstance().getDataCenter().retrieveData();
}
@Override
protected void onDraw(Canvas canvas) {
Log.i(TAG, "onDraw");
super.onDraw(canvas);
for(int i=0;i<data.size();i++){
canvas.drawText(data.get(i), 100f, 100f + i*40f, mPaint);
}
}
public static void show(){
Log.d(TAG, "show");
}
private List<String> data = new ArrayList<String>();
@Override
public void update(Observable observable, Object data) {
this.data = MyApplication.getInstance().getDataCenter().retrieveData();
invalidate();
}
}
DataCenter.javapublic class DataCenter extends Observable{
private List<String> strs = new ArrayList<String>();
public List<String> retrieveData(){
return strs;
}
public void changeData(String data){
this.strs.add(data);
setChanged();
notifyObservers(null);
}
}
4、不變模式(Immutable Pattern)不變模式即對象一旦創建其狀態就不再變化,常見的有String(封裝char[])、Integer(封裝int)等
//不變子模式
//String封裝一個char[]
String str = "welcome";
String str2 = new String(str);
String str3 = "welcome";
//相同對象
System.out.println("str==str3:"+(str==str3));
//不同對象但hashCode相同
System.out.println("str:"+str.hashCode()+";str2:"+str2.hashCode());
System.out.println(str.equals(str2)+"-"+(str==str2));
//final類,繼承Number,將基本類型long封裝爲Object
//實例化時傳入值,不再改變
Long l = new Long(5L);
Float f = new Float(5.0f);
//有些地方只能用Object,需要wrapper
Vector<Long> vector = new Vector<Long>();
vector.addElement(5L);
5、多例模式(Multiton Pattern)
多例模式特點爲類不能從外部實例化,自行創建並向外部提供多個實例。多個實例使用私有靜態聚集保存。
Locale locale = Locale.CHINA;//new Locale("zh", "CN");
//src目錄下 bundle_zh_CN.properties
//使用了多例模式,支持多語言
ResourceBundle rb = ResourceBundle.getBundle("bundle", locale);
Log.d(TAG, rb.getString("name")+"-"+rb.getString("sex"));
//HashTable key/value必須string
Properties properties = new Properties();
properties.put("height", "175CM");
properties.put("weight", "70KG");
properties.setProperty("address", "BJ");//直接調用Hashtable.put
try {
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory()+"/info.xml");
FileInputStream fis = new FileInputStream(Environment.getExternalStorageDirectory()+"/info.xml");
properties.storeToXML(fos, null, "UTF-8");
properties.loadFromXML(fis);
properties.getProperty("height");//Hashtable.get
properties.list(System.out);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
bundle_zh_CN.properties
name=\u77f3\u946b
sex=male
6、listener模式
private static class DataDecodedListenerWrapper{
boolean full;
DataDecodedListener listener;
public DataDecodedListenerWrapper(boolean full,
DataDecodedListener listener) {
this.full = full;
this.listener = listener;
}
@Override
public boolean equals(Object o) {
DataDecodedListenerWrapper wrapper = (DataDecodedListenerWrapper) o;
if(this.listener==wrapper.listener&&this.full==wrapper.full){
return true;
}
return false;
}
}
/**
* <li>此處接口也用extends
* <li>key用value的class保證某個類的對象僅存一個
*/
private Map<Class<? extends DataDecodedListener>, DataDecodedListener> mMap = new HashMap<Class<? extends DataDecodedListener>, BaseDecoder.DataDecodedListener>();
private List<DataDecodedListenerWrapper> mListeners2 = new ArrayList<DataDecodedListenerWrapper>();
private Map<DataDecodedListener, Boolean> mMap2 = new HashMap<DataDecodedListener, Boolean>();
public void registerListener2(DataDecodedListener listener, boolean full){
// synchronized (mMap) {
// if(!mMap.containsValue(listener)&&mMap.containsKey(listener.getClass())){
// mMap.remove(listener.getClass());
// mMap.put(listener.getClass(), listener);
// }
// }
synchronized (mMap2) {
if(!mMap2.containsKey(listener)){
mMap2.put(listener, full);
}
}
}
public void unregisterListener2(DataDecodedListener listener){
// synchronized (mMap) {
// mMap.remove(listener.getClass());
// }
synchronized (mMap2) {
mMap2.remove(listener);
}
}
public void notifyAllDataDecodedListener(BaseDecoder decoder) {
// synchronized (mMap) {
// Set<Entry<Class<? extends DataDecodedListener>, DataDecodedListener>> set = mMap.entrySet();
// Iterator<Entry<Class<? extends DataDecodedListener>, DataDecodedListener>> it = set.iterator();
// while(it.hasNext()){
// DataDecodedListener listener = it.next().getValue();
// listener.onHealthDataDecoded(decoder);
// }
// }
// synchronized (mListeners2) {
// Iterator<DataDecodedListenerWrapper> it = mListeners2.iterator();
// boolean full = BqfjApplication.isFullscreenMode();
// while (it.hasNext()) {
// DataDecodedListenerWrapper listenerWrapper = it.next();
// if (listenerWrapper.full==full) {
// listenerWrapper.listener.onHealthDataDecoded(decoder);
// }
// }
// }
synchronized (mMap2) {
Set<Entry<DataDecodedListener, Boolean>> set = mMap2.entrySet();
Iterator<Entry<DataDecodedListener, Boolean>> it = set.iterator();
boolean full = BqfjApplication.isFullscreenMode();
while(it.hasNext()){
Entry<DataDecodedListener, Boolean> entry = it.next();
DataDecodedListener listener = entry.getKey();
if(entry.getValue()==full)
listener.onHealthDataDecoded(decoder);
}
}
}