先解释一下设计模式之美,美体现在哪里?
任何实现代码的方法都没有美丑之分,只有复杂与简单之分,人们喜欢简单的,害怕、厌烦、排斥复杂的。
设计模式之美就体现在可以把复杂的东西简单化,让人们用起来很简单,不再惧怕复杂,这就是设计模式美的体现。
Android框架乍一看很复杂,实际上应用了很多设计模式,所以如果我们从设计模式角度来分析Android框架,也就很简单了。
Template Method 即 模板方法
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();}}
下面就应用“变与不变的原则”,来优化上面的案例。
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();
}}
接着就可以看看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内核剖析》中的第五章。