第 4 天
框架开发者学习指南(Day-04)
-- 实例演练
学习步骤:
Step 4.1 前言:在昨天学习指南(Day-03)里,已经看过<餐厅的点菜单>的范例了。一旦谈到餐厅里攸关于桌子和锅子的知识,就很容易联想到烹饪的知识,它分散于两种文件里:食谱和点菜单。一般而言,食谱主要记载烹饪师傅的知识,而点菜单则记载买主(客人)的知识;两者相汇合之后,才能端出一道好吃的菜肴。如下图所示:
(图4-1)
基于上述食谱和点菜单的例子,就很容易对应到软件框架开发了。于买主(客户或用户)出现之前,软件开发者基于他们已具备的知识,来决定接口;然后把其知识(包括领域通用需求和开发技能)写在框架基类里;并且提供<I>接口。
基于<I>接口,当买主出现了,才把买主的知识(即需求)写入于应用子类里。如下图所示:
(图4-2)
在软件开发上,厘清或萃取知识(Knowledge Acquisition)的任务,通称为需求分析(Requirement Analysis)。在框架设计上,我们最关键的是要去厘清领域知识与买主知识的分际,通常不需要对需求细节多下功夫。因此,配合开发框架而做的需求分析,与传统的系统开发需求分析并不完全一样。于是,我们常对前者称之为:框架需求分析。
Step 4.2 复习:主板模式(Motherboard pattern)。在昨天学习指南(Day-03)里,已经看过主板模式的两种不一样的结构了。例如,典型的结构,如下图所示:
(图4-3)
Step 4.3 复习:框架需求分析。将软件开发分为三个阶段,一般而言,软件开发者都很能区分软件的「开发」与「执行」两个阶段。如果我们再依循上一节所提的『买主来了』时间点,来将开发阶段分为两段,就成为3个阶段了。如下图:
(图4-4)
厘清这3个阶段之后,就可以演练进行一个简单的动作:把领域(和架构师)知识写入基类里,然后把买主需求写入到子类里。此外,还要定义两者之间的<I>接口,让基类可以调用子类的函数,以便执行子类的代码,将执行结果汇合到基类里。如下图:
(图4-5)
Step 4.4 实操演练:题目(一)
- 需求分析
在学习Java编程时,几乎大家都写过一个简单的应用程序,就是求算1+2+3+ … + N的值。依据上一小节的需求时间轴概念,可绘图如下:
(图4-6)
从上图可引导你决定三件事:
1.算法(1+2+3+… +N)必须撰写于框架的基类里。
2.N值必须撰写于应用子类里。
3.基类必须调用子类去取的N值。
决定了,就可以依据上图4-4到图4-6的思维而绘制出类别设计图,如下所示:
(图4-7)
其中的ICount接口内含抽象函数的定义。如果你想加上一些预设行为(Default Behavior)函数,就可以设计抽象类来取代之。如下图:
(图4-8)
虽然BaseAdpater与ICount的架构形式不同,但其都担任接口的角色,让myCounter能顺利装配到Counter上。在BaseAdpater里可以加上其它的具象函数来表达一些预设行为,呈现框架的深度服务。这些预设行为,一方面可用来简化myCounter内容,减轻其开发者的负担。在另一方面,则能用来调整接口本身,让Counter与myCounter两者之间更具有独立性,降低两者之间的相依性(Dependency);此时,它扮演调节器(Adapter)的角色。
(图4-9)
这BaseAdapter将onCount()接口函数转换成为getCount()函数;其让Clounter与myCounter各使用不同接口函数,有利于双方的稳定而独立成长。
- 撰写代码
首先建立一个Android的Ex05_01项目(Project),如下:

★ 撰写你的框架基类和<I>
// BaseAdapter.java
package myFramework;
public abstract class BaseAdapter {
// 其它函数
public int getCount() {
int n = this.onCount();
if( n<0 ) n = 0;
return n;
}
protected abstract int onCount();
}
// Counter.java
package myFramework;
public class Counter {
private BaseAdapter reference;
public int run() {
int N;
N = reference.getCount();
int sum = 0;
for(int i=1; i<=N; i++) {
sum += i;
}
return sum;
}
public void setRef(BaseAdapter co){
reference = co;
}
}
★ 把基类和<I>送人,协助别人去开发应用子类
// myCounter.java
package com.misoo.pk07;
import myFramework.BaseAdapter;
public class myCounter extends BaseAdapter{
@Override
public int onCount() {
return 10;
}
}
// myActivity.java
package com.misoo.pk07;
import myFramework.Counter;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
public class myActivity extends Activity implements OnClickListener{
private Button ibtn;
private Counter counter;
@Override protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
ibtn = new Button(this);
ibtn.setOnClickListener(this);
ibtn.setText("Exit");
ibtn.setBackgroundResource(R.drawable.gray);
LinearLayout.LayoutParams param1 =
new LinearLayout.LayoutParams(150, 65);
param1.topMargin = 10;
param1.leftMargin = 5;
layout.addView(ibtn, param1);
setContentView(layout);
//---------------------------------------------
counter = new Counter();
counter.setRef(new myCounter());
int sum = counter.run();
setTitle("sum = " + String.valueOf(sum));
}
public void onClick(View arg0) { finish(); }
}
此程序计算了1+2+3+… +10,输出结果:55。

- 改变设计图
在架构层面上,你可以将上图4-9里的Counter与BaseAdapter两个类别合并起来。这是框架开发者的自由调解范围,只要不改变onCount()接口函数,就不会影响到myCounter了。如下图:
(图4-10)
// Counter.java
package myFramework;
public abstract class Counter {
public int run() {
int N;
N = this.onCount();
int sum = 0;
for(int i=1; i<=N; i++)
sum += i;
return sum;
}
public abstract int onCount();
}
// myCounter.java
package com.misoo.pk07;
import myFramework.Counter;
public class myCounter extends Counter{
public int onCount() { return 10; }
}
Step 4.5 实操演练:题目(二)
- 需求分析
如果时间轴改为:
(图4-11)
现在可以试试先想想接口设计:基类必须有个抽象函数,来反向调用到子类。在调用该函数时,顺便把基类里的N值传递下去给子类。由子类进行计算工作,然后将计算结果传回给基类。亦即,你可做下述三件事:
- 将N值写在框架基类里。
- 替各买主而设计一个子类,将各自采取的算法(如1^1 + 2^2 + 3^3 +… +N^N)撰写于子类里。
- 替基类设计一个抽象函数onCal(n:int),让基类能调用子类,取得子类的计算结果。
- 撰写代码
请您参考前面Step 4.4的流程,建立一个Android应用开发项目(Project),并将上图4-11的框架需求分析图,实现为Android的App代码,并实际执行之。
PS.可参考文章:好莱坞(Hollywood)原则的演练
Step 4.6 实操演练:题目(三)
- 需求分析
如果时间轴改为:
((图4-12)
现在可以试试先想想接口设计:基类必须有个抽象函数,来反向调用到子类。基类可以重复调用该函数,总共调用N次,每次回传一个Kn值,在由基类把它们累加起来。当然,你也能设计一个新的接口函数,基类只调用它一次,调用时把N值传递下去给子类。由子类回传N项数据,例如从数据库里读取N笔数据并回传给基类。由于接口函数的制定权就掌控于你(框架设计者)的手中,App开发者会配合你的。
- 撰写代码
请您参考前面Step 4.4的流程,建立一个Android应用开发项目(Project),并将上图4-12的框架需求分析图,实现为Android的App代码,并实际执行之。
PS.可参考文章:好莱坞(Hollywood)原则的演练
Step 4.7 实操演练:题目(四)
- 需求分析
如果时间轴改为:
(图4-13)
依据此图4-13,您可以使用Activity来提供UI上的一个EditText窗口,让User在执行阶段才输入N值。由基类主动去向Activity的 EditText取得N值,然后重复调用接口函数,总共调用N次,每次回传一个Kn值,在由基类把它们累加起来。于是,设计出架构图,如下:
(图4-14)
- 撰写代码
请您参考前面Step 4.4的流程,建立一个Android应用开发项目(Project),依据上图4-14的框架需求分析图,以及图4-15的架构图,开发Android的App代码,并实际执行之。
PS.可参考文章:好莱坞(Hollywood)原则的演练
Step 4.8 观摩与讨论:
- 针对Web Shop用例进行分组讨论,提出业务框架的初步设计方案
- 基于初步方案来进行优化,提出高可用的实践方案
~ End ~