您的位置:首页 > 移动开发 > Android开发

Android应用框架魅力的泉源--反向沟通

2016-05-10 11:49 555 查看
今天看到一篇特别好的文章,深受启发,对之前的应用框架的认识有了颠覆性的改变,非常感谢高焕堂大神的倾力奉献!

对于文章标题是转载还是原创,我纠结了一下。想到我只是在他的书上节选一段,进行编辑和细微修改,就转载好了~

下载地址:http://download.csdn.net/download/zhoujiamurong/1470442

文章名为:Android 应用框架原理与程序设计36 技

2.2.1正向沟通
传统的链接库(FunctionLibrary)已含有许多现成的函數(前辈),您的程序(晚辈)可呼叫之。例如,
publicmyFunction() {
int x =abs( y );
……
}
abs()是您已很熟悉的库存函數,它诞生在先,是前辈;您的程序(晚辈)诞生在后,是晚辈。这是传统呼叫法:晚辈呼叫前辈。一般類别库(ClassLibrary)含有现成的類别,这些類别含有函數,可供新類别的函數來呼叫之。例如,先有个Person 父類别如下:
publicclass Person {
privateString name;
publicvoid SetName(String na) { name = na; }
publicvoid Display()
{System.out.println("Name: " + name ); }
}
接着,您可以写个子類别Customer去继承它,并且呼叫它的函數,如下:
publicclass Customer extends Person {
publicvoid Init() { super.SetName(“Tom”); }
publicvoid Show() { super.Display(); }
}
上述的Init()呼叫了晚辈SetName()函數。或者,写个JMain 類别:
publicclass JMain {
privatep;
publicvoid Init() {
p = newCustomer();
p.SetName(“Tom”);
}
publicvoid Show() { p.Display(); }
}
这也是晚辈呼叫前辈的情形。由于大家已习惯了这种晚辈呼叫前辈的用法, 就通称为「正向」(Forward)呼叫法。由于晚辈拥有主控权,所以这种机制
又称为「正向控制」。再來看看本书的主角:Android 框架,以下就是Android 的应用程式码:
//Android 程序
publicclass MyActivity extends Activity {
@Override
publicvoid onCreate(Bundle icicle)
{super.onCreate(icicle);
setContentView(R.layout.main);
}
上述晚辈(即MyActivity)的onCreate()呼叫了晚辈(即Activity)的onCreate()和setContentView()函數。而Activity 就是Android 框架裡的重要抽象類别。
2.2.2反向沟通
当子類别继承父類别时,父類别之函數可以呼叫子類别之函數。虽然父類别(前辈)诞生时,子類别(晚辈)常常尚未诞生﹔但是前辈有时候可预知晚辈中的函數,就可呼叫它。框架裡的抽象類别就是扮演父類别的角色,只是含有一些阳春型的類别,其提供很通用,但不完整的函數,是设计师刻意留给应用程序的子類别來补充的。一旦补充完成,框架裡的父類别的函數就可以「反向呼叫」子類别裡的函數了。
2.2.2.1以一般Java
程序为例
例如:有了一个绘图的Shape 父類别:
//Shape.java
package_framework;
publicclass Shape {
publicvoid Paint() { this.Draw(); }
publicabstract void Draw();
}
设计者预期子類别将会定义一个Draw()函數,于是让Paint()呼叫子類别的Draw()函數。于是子類别(晚辈)提供Draw()给父類别(前辈)來呼叫之,如下:
ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ
// Circle.java
package _objects;
import java.awt.Color;
import java.awt.Graphics;
import _framework.*;
public class Circle extends Shape {
private Graphics m_gr;
private int x, y, radius;
public Circle(Graphics gr) { m_gr = gr; }
public void SetValue(int x0, int y0, int rad){
x = x0; y = y0;
radius = rad;
}
public void Draw(){ //画圆
m_gr.setColor(Color.BLACK);
m_gr.drawOval(x-radius, y-radius, 2*radius, 2*radius);
}}
接者,写个JMain 類别:
// JMain.java
import java.awt.*;
import javax.swing.*;
import _framework.Shape;
import _objects.*;
class JP extends JPanel {
public void paintComponent(Graphics gr) {
super.paintComponents(gr);
Circle cir = new Circle(gr);
cir.SetValue(160, 100, 45);
Shape sp = cir;
sp.Paint();
}}
public class JMain extends JFrame {
public JMain() { setTitle(""); setSize(400,300); }
public static void main(String[] args)
{ JMain frm = new JMain();
JP panel = new JP();
frm.add(panel);
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setVisible(true);
38 Android 应用框架原理与程序设计36 技
ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ
}}
此程序执行到JP 類别的sp.Paint()指令时,就呼叫到Shape 父類别的Paint()函數,接着就呼叫到Circle 子類别裡的Draw()函數了。这种前辈呼叫晚辈的用法, 就通称为「反向」(Inversion) 呼叫法。由于前辈拥有主控权,所以这种机制又称为「反向控制」(Inversion ofControl)。
2.2. Android
程序为例
例如想在Android 上画出一个长方形,可写程序如下:
// Android 程序
public class MyView extends View {
private Paint paint;
public MyView(Context context) {
super(context);
private Paint paint= new Paint();
}
public void ReDraw() { this.invalidate(); }
@Override
protected void onDraw(Canvas canvas) { // 画长方形
paint.setAntiAlias(true);
paint.setColor(Color.YELLOW);
canvas.clipRect(30, 30, 100, 100);
}}
程序执行到ReDraw()函數时, 就正向呼叫到Android 框架裡的invalidate()函數了。接着,Android 框架会反过來呼叫MyView 子類别的onDraw()函數。这就是「反向沟通」了。如果你没有定义onDraw()函數的话,会执行View 父類别预设的onDraw()函數,而依据框架预设之惯例而行了。
ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ
2.3 主控者是框架,而不是应用程序
前面說过,传统的链接库及類别库只提供正向沟通,而应用框架则提供正向和反向兼具的双向沟通。本节针对应用框架的双向沟通,做进一步的阐述双向沟通机制让框架成为主控者,而应用程序只是配角而已。首先看个例子,假设已经设计了Person 及Customer 兩類别并存于应用框架中,如下图所示:



图2-2 一个简单的框架
兹以Java 程序表达如下:
// Person.java
package _abstract_classes;
public abstract class Person {
protected String name;
public void setName(String na) { name = na; }
public abstract void display();
}
// Customer.java
package _abstract_classes;
public class Customer extends Person {
public void display()
{ System.out.println("Customer: " +super.name); }
}
现在,基于这个框架而衍生出VIP 子類别,如下图:



图2-3 衍生出应用程序的類别
其Java 程序代码如下:
// VIP.java
package _concrete_classes;
import _abstract_classes.*;
public class VIP extends Customer {
private String tel;
public VIP(String na, String t) {
super.setName(na);
tel = t;
}
public void display()
{ super.display();
System.out.println("TEL: " + tel);
}}
Customer
ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ
建构式VIP() 呼叫父類别的setName() 函數, 且display() 呼叫Customer::display()函數,这兩者皆为正向沟通。亦即,程序中的函數呼叫框架中的函數。现在继续增添反向沟通机制。例如,于框架中增加了Product 類别,此时,框架共含三个類别。基于这框架,您可衍生出子類别如下图所示:



图2-4 框架掌握更多主控权
其Java 程序代码如下:
// Product.java
package _abstract_classes;
public abstract class Product {
protected int pno;
protected Customer cust;
public Product(int no) { pno = no; }
public void soldTo(Customer cobj) { cust = cobj; }
public void inquire() {
this.print();
System.out.println("sold to ...");
cust.display();
}
ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ
public abstract void print();
}
// TV.java
package _concrete_classes;
import _abstract_classes.*;
public class TV extends Product {
private double price;
public TV(int no, double pr) {
super(no); price = pr;
}
public void print()
{ System.out.println("TV No: " + pno);
System.out.println("Price: " + price);
}}
其反向沟通机制如下图:
public class Product {
....
public void inquire() {
public class Person {
....
}
(反向沟通)
}
....
this.print();
cust.display();
(反向沟通)
public class Customer
extends Person {
....
}
}
public class TV extends Product {
....
public void print()
....
}}
public class VIP
extends Customer {
....
public void display() {
....
继续看个主函數,会更清晰地理解框架的主控地位,如下程序代码:
// JMain.java
import _abstract_classes.*;
ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ
import _concrete_classes.*;
public class JMain {
public static void main(String[] args)
{ TV t = new TV(1100, 1800.5);
VIP vp = new VIP("Peter","666-8899");
t.soldTo(vp);
t.inquire();
}}
Product 父類别设计在先,然后才衍生TV 子類别,而且常由不同人所设计。那么,何以Product 類别的inquire() 敢大胆地呼叫TV 類别的print()
函數呢﹖万一TV 類别并无print()时,怎么办呢﹖答案很简单:
☆ TV 類别必须定义print()函數,才能成为具体類
别。因为Product 裡的print()是抽象函數,内容
从缺:
public abstract void print();
其中的abstract 字眼,指示子類别必须补充之,才能成为具体類别。
☆ TV 類别成为具体類别,才能诞生对象。
☆ 有了对象才能呼叫inquire()函數,
☆ 既然TV 類别已覆写print()函數,inquire() 可大胆地呼叫
之。于是,必须替TV 類别添增print()函數如下:
public void print()
{ System.out.println("TV No: " + pno);
System.out.println("Price: " + price);
}
执行时,__________就产生反向呼叫的现象了。此外,Product 類别的inquire() 呼叫VIP 類别的display()函數。Product類别与VIP 類别并非同一个類别体系。此时,VIP 類别必须是具体類别才能诞生对象。cust 变數必须參考到刚诞生的对象。由 cust 所參考之物件來执行其display()函數。inquire()就透过cust 而成功地呼叫到VIP 類别的display()了。
ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ
这过程有个先决条件──VIP 類别必须覆写display()函數才行。否则将会呼叫到Customer 類别预设的display(),而不是呼叫到VIP 類别的display()函數。也许,您还会问一个问题:何不将cust 变數改宣告为VIP 型态之參考呢﹖答案是: 别忘了,抽象類别通常设计在先,而具体類别产生在后。因之,设计Product 類别时,VIP 類别尚未诞生呢﹗ 这程序展现了应用框架的重要现象:
☉程序执行时,主控权在框架手上。
虽然main()函數仍为程序的启动者,但主要的处理过程皆摆在Product類别内。例如,
● soldTo()负责搭配产品与顾客之关系。
● inquire() 负责呼叫TV 的print() 输出产品资料,并呼叫VIP

display() 输出顾客资料。
☉程序裡的類别,其成员函數,主要是供框架呼叫之。
例如,TV 類别的print()供inquire()呼叫之,而VIP 類别的display()供inquire()呼叫之。
☉由于框架掌握主控权,复杂的指令皆摆在框架中,大幅简化应用程序。因之,优良的应用框架常让程序员如虎添翼。
☉框架裡的inquire() 进行反向沟通,它呼叫子類别的print()
函數。这是同体系内的反向呼叫。
☉框架裡的inquire() 反向呼叫VIP display()
函數。因Product 与VIP 分属不同的類别体系。这是跨越体系的反向沟通。
 

2016.5.10 北京天气晴朗,早晚穿长袖,其他时间半袖就OK了。今天周二,看到这篇文章让我很兴奋,所以分享给大家~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: