Android设计模式之美---Template Method


转载请表明出处:http://write.blog.csdn.net/postedit/43411673

先解释一下设计模式之美,美体现在哪里?

任何实现代码的方法都没有美丑之分,只有复杂与简单之分,人们喜欢简单的,害怕、厌烦、排斥复杂的。

设计模式之美就体现在可以把复杂的东西简单化,让人们用起来很简单,不再惧怕复杂,这就是设计模式美的体现。

Android框架乍一看很复杂,实际上应用了很多设计模式,所以如果我们从设计模式角度来分析Android框架,也就很简单了。

Template Method 即 模板方法

谈到模板方法,首先我们要了解 “变与不变的原则”,何谓“变与不变的原则”,我用一个例子来说明一下。
大家都用过一种多功能的螺丝刀吧,手柄部分只有一个,但是却有很多很多的头。
         Android设计模式之美---Template Method_第1张图片
很显然,这个手柄部分就是一直不变的不分,各种各样的头就是变的部分,这样就明白了“变与不变的原则”。
而在程序中,变的部分是需要不用场景不同实现的,不变的部分是一直不变,需要抽离出来的。
在螺丝刀中,插头的地方叫卡槽,卡槽属于手柄的一部分。
相对应到程序中,插头的地方叫卡榫函数,手柄是Tempalte函数。
而“变与不变”,无关乎本质,只在于看事请的角度。


通过一大推的描述来解释一个定义,我觉得这种学习方法不适合程序员。我还是直接用代码来解释吧。
首先来看没有应用任何设计模式的案例。

public class AA {
private String x;
AA(String str){ x = str; }
public void print(){ System.out.println(x); }
}

public class BB {
private int x;
BB(int k){ x = k; }
public void print(){ System.out.println(x); }
}

public class JMain {
public static void main(String[] args) {
AA a = new AA("hello");
BB b = new BB("hello girl");
a.print();
b.print();}}
 
 
 
  
 
  

下面就应用“变与不变的原则”,来优化上面的案例。

将变与不变的地方分离开来,然后将会变得地方写入卡榫函数,比如卡榫函数命名为“hook_getData()”。
private String x;
public final void template_print() {
System.out.println( hook_getData() ); }
public String hook_getData() { return x;
}

private int x;
public final void template_print() {
System.out.println( hook_getData() ); }
public String hook_getData() { return String.valueOf(x);
}



分离之后,template_print()函数含有不变的部分,而hook_getData()函数会含有变得部分。

接着再引入父子继承关系,将不变的template_print()函数提到父类中。

在父类中,定义抽奖的hook_getData()卡榫函数。

在父类中,在template_print()函数中调用抽象的卡榫函数hook_getData(),此时由继承机制反向(一般认为由子类调用父类的方法为正向)呼叫子类别的hook_getData()函数,实现了父、子类别之间的不同调用。

相对于Android框架来讲,temlate_print()函数将会吸收在框架里,hook_getData()函数将会被纳入到应用程序里。

这就是框架与应用程序之间的沟通了,hook_getData()卡榫函数起着桥梁的作用。

程序如下:


public abstract class SuperAB {
public void template_print(){
System.out.println(hook_getData());
}
protected abstract String hook_getData();
}

public class AA extends SuperAB{
private String x;
AA(String str){ x = str; }
@Override protected String hook_getData() {
return x;
}}

public class BB extends SuperAB{
private int x;
BB(int k){ x = k; }
@Override protected String hook_getData() {
return String.valueOf(x);
}}

public class JMain {
public static void main(String[] args) {
AA a = new AA("hello");
a.template_print();
}}


此时,你可以将SpuerAB纳入AF(应用框架,Android Framework)里,于是JMain类别里的指令:
a.template_print();
呼叫了AF里的template.print()函数。
AF里的template.print()函数调用了SuperAB类里面的hook_getData()函数,进而反向呼叫了AP(SuperAB的子类)
里的hook_getData()函数。这也就是反向控制,或者说是控制反转。
到这里就明白了“变与不变的原则”,明白了控制反转。
对外的接口是tempalte_print(),
对内的接口是hook_getData(),
这样就屏屏蔽掉了传统父类和子类用一个接口产生的依赖性,提高了应用框架的弹性。这就是Template Method模式的用处所在。

接着就可以看看Template Method 模式在Android中的应用了。

public class ac01 extends Activity implements View.OnClickListener {
	private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;
	private final int FP = LinearLayout.LayoutParams.FILL_PARENT;
	private static ac01 appRef = null;
	private myButton btn, btn2, btn3;
	public TextView tv;
	private IBinder ib;

	public static ac01 getApp() {
		return appRef;
	}

	public void btEvent(String data) {
		setTitle(data);
	}

	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		appRef = this;
		LinearLayout layout = new LinearLayout(this);
		layout.setOrientation(LinearLayout.VERTICAL);
		btn = new myButton(this);
		btn.setId(101);
		btn.setText("play");
		btn.setOnClickListener(this);
		LinearLayout.LayoutParams param =
				new LinearLayout.LayoutParams(btn.get_width(), btn.get_height());
		param.topMargin = 10;
		layout.addView(btn, param);
		btn2 = new myButton(this);
		btn2.setId(102);
		btn2.setText("stop");
		btn2.setOnClickListener(this);
		layout.addView(btn2, param);
		btn3 = new myButton(this);
		btn3.setId(103);
		btn3.setText("exit");
		btn3.setOnClickListener(this);
		layout.addView(btn3, param);
		tv = new TextView(this);
		tv.setTextColor(Color.WHITE);
		tv.setText("Ready");
		LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC);
		param2.topMargin = 10;
		layout.addView(tv, param2);
		setContentView(layout);
		bindService(new Intent(ac01.this, mp3Service.class), mConnection, Context.BIND_AUTO_CREATE);
	}

	private ServiceConnection mConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder ibinder) {
			ib = ibinder;
		}

		public void onServiceDisconnected(ComponentName className) {
		}
	};

	public void onClick(View v) {
		switch (v.getId()) {
		case 101:
			tv.setText("Playing audio...");
			setTitle("MP3 Music");
			try {
				ib.transact(1, null, null, 0);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			break;
		case 102:
			tv.setText("Stop");
			try {
				ib.transact(2, null, null, 0);
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			break;
		case 103:
			finish();
			break;
		}
	}
}

public class mp3Service extends Service {
	private IBinder mBinder = null;
	@Override public void onCreate() {
		mBinder = new mp3PlayerBinder(getApplicationContext());
	}
	@Override public IBinder onBind(Intent intent) { return mBinder; }
}

public class mp3PlayerBinder extends Binder {
	private MediaPlayer mPlayer = null;
	private Context ctx;

	public mp3PlayerBinder(Context cx) {
		ctx = cx;
	}

	@Override
	public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
			throws android.os.RemoteException {
		if (code == 1)
			this.play();
		else if (code == 2)
			this.stop();
		return true;
	}

	public void play() {
		if (mPlayer != null)
			return;
		mPlayer = MediaPlayer.create(ctx, 0);
		try {
			mPlayer.start();
		} catch (Exception e) {
			Log.e("StartPlay", "error: " + e.getMessage(), e);
		}
	}

	public void stop() {
		if (mPlayer != null) {
			mPlayer.stop();
			mPlayer.release();
			mPlayer = null;
		}
	}
}

public class myButton extends Button {
	public myButton(Context ctx) {
		super(ctx);
	}

	public int get_width() {
		return 80;
	}

	public int get_height() {
		return 50;
	}

}

整好借这个例子,也能学习一下Binder的用处。如果想学习Binder的用法,我推荐《Android内核剖析》中的第五章。

Tempate Method模式就好比一只乌龟,轻易看不到乌龟的头,template函数就是乌龟的头,hook函数就是乌龟的尾巴,
我们一般只能看到乌龟的尾巴。
在Android的Binder父类中定义了一个transact()函数,这就是乌龟的头,它会呼叫onTransact()卡榫函数,也就是尾巴。

这样我们就明白了Android Binder 虽然看似复杂,但是从Template Method角度来看,是简单而美的一种很有序的设计实现,
而不是杂乱无章,很高深莫测的。

好人做到底,提供一下最后一个Android Binder 案例 demo的下载地址:

https://github.com/nicewarm/EIT_Template_Method



你可能感兴趣的:(设计模式,框架,android)