框住App的架构及行为

    框架的基类必须与应用子类互相紧密结合,其目的就是想要<框住>应用子类的行为。框架基类可分为两种:

  • 具象类(Concrete Class) -- 这是一般的类。它是具体而完整的类,它的每一个函数都有完整的实现代码,这种函数通称为具象函数。这是大家已经熟悉的类了,我们可以随意拿它来创建对象(Object)。

  • 抽象类(Abstarct Class) -- 除了具象函数之外,还定义了抽象函数,来实现(Implement)框架API。抽象类是不完整的,预留一些空间,等待子类来填补之。例如,建房子时,师傅都会预留一些卡榫,可做未来衔接点。例如,从具体类抽掉某些函数的实作(Body)部分,这些函数就称为抽象函数(Abstract Function),而含有抽象函数的类就称为抽象类了。由于这种抽象类本身不能产生对象,而必须由子类来将其抽象函数的实现代码部分补充起来才是完整的,才能拿来创建对象。抽象类必然扮演基类的角色。 

    上述的抽象函数都扮演着卡榫(Hook)函数的功能,用来支持并<框住>应用子类的结构和行为。如下图所示: 

  

抽象函数扮演卡榫角色

    在应用框架里,这种抽象函数扮演着<卡榫(Hook)>的角色。所谓卡榫,就是用来接合两个东西(例如父、子类)的接口。如果两个东西于不同时间出现,则一方会预留虚空,给予另一边于未来时刻能以实体来填补该空间,两者虚实相依,就密合起来了。设计优良的卡榫,可以让实体易于新陈代谢、抽换自如(Plug and Play, 俗称PnP)。卡榫函数在应用框架里扮演重要角色,它与应用子类(简称App)是虚与实的两方,而且两者是不同时间出现,通常是前者先出现,才能<框住>后者。因此,应用框架必须藉由卡榫函数去预留虚空,让后来的应用子类(App)来填补该空间,两者虚实相依,就密合起来了。于是,框架设计师负责撰写抽象类,而App开发者负责撰写子类。两者跨时间和空间的智能会合而成为一支完整的应用软件。

    抽象函数是父、子类之间的卡榫接口处。在应用框架里有许多抽象的父、子类,需要卡榫函数来衔接;此外,框架里的父类与App里的子类之间,也需要藉由卡榫函数来接合。所以处处可见到卡榫函数的身影。如果父类是位于框架里,而其子类是位于App里,则抽象函数就扮演框架与应用类之间的卡榫功能了,也就是所谓的框架API了。譬如,Android的框架基类Activity提供onCreate()可覆写(抽象)函数扮演卡榫角色;另一个基类View也提供onDraw()可覆写(抽象)函数函数扮演卡榫角色。如下图所示:

  

抽象函数实现<反向控制(IoC)>

    顾名思义,IoC(Inversion of Control)就是「反向控制」之意思。IoC观念和机制源自于OOP语言(如C++、Java等)的类继承(Inheritance)机制,例如Java语言中,基类的函数可以主动调用子类的函数,这就是一般所谓的IoC机制。IoC反向控制又称为:<反向调用>,或称为<反向调用>。<反向调用>的相反词是:正向调用。正向调用就是App子类调用基类的函数。例如,下图里的FirstActivity应用子类调用Activity基类的setContentView()具象函数。

  

    至于反向调用,则恰好相反,其意味着:由基类调用子类的函数。例如,下图里的Activity透过可覆写的onCreate()函数而调用到FirstActivity应用子类的onCreate()函数。

  

     由应用子类主动正向调用基类的函数,就意味着正向控制,也就是说,App 子类控制了框架基类,这是违背框架设计原则的。这项设计原则就如同好莱坞(Hollywood)大明星的名言:“Don’t call me, I’ll call you back.”,如下图:

  

    上图所示的正向控制,既违背了好莱坞大明星的原则,也违背框架设计的原则。那么,该如何修正呢? 改为反向控制就行了。无论是IoS或Android框架的设计,都依循着这项基本原则,让框架掌握控制权,让框架能框住应用程序。所以,如上图所示,应用子类不宜主动正向调用框架基类。只有当框架基类反向调用应用子类的时候,应用子类才能被动地正向调用框架基类。如下图所示:

  

      反向调用就意味着反向控制,也就是说,框架基类控制了App 子类,这是符合框架设计原则的,也符合好莱坞大明星的“Don’t call me, I’ll call you back.”原则。

~ end ~