Java及Android常用設計模式

在你的程序中應用一些設計模式讓你的代碼組織更有條理。懂得設計模式讓你更容易看懂一些優秀的源碼。本文逐步摸索各種設計模式。

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.java
public 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.java
public 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.java
public 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.java
public 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);
		}
	}
}

發佈了56 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章