• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
 






高煥堂.EIT

 
 

Powered by 博客园
博客园 | 首页 | 新随笔 | 联系 | 订阅 订阅 | 管理

Framework-zz-34

 By 高焕堂

  

ee                                                                   ee 

【思考Android技术】 

 請參考:Android从程序员到架构师之路课程(在线视频学习) 

 请进入:ADT架构师学苑  

ee                                                                   ee

 

框架如何写模版去读App所订的接口?

 

      大家都知道AP开发者实现框架里所定的接口。意味着,框架开发者订定接口给AP开发者来使用。然而,AP开发者也能订定接口来给框架开发者来使用呀!

  

1. 前言

    在前面的文章里,例如:

  • <<框架的主要元素:基类与API>>
  • <<框架主动型API幕后的IoC机制>> 

所谈到的接口都是由框架开发者所设计或制定;例如,设计基类的抽像函数,让应用程序开发者来撰写这些抽像函数的代码。也就是说,上述文章所谈的都是:

  • 由框架开发者制定接口;
  • 由应用程序开发者撰写代码。 

      在本文里,则将其颠倒过来,改由框架开发者来撰写代码;而由应用程序开发者来制定接口;此时模板(Template)技术就变得非常重要了。希望你阅读本文之后,就能活用模板来替应用程序开发者做更多的服务。也更丰富了框架的内涵了。

 

2. 模版介绍

      模版(Template)可用来重复使用以便创造出一序列相类似的东西。当我们使用印章时,就在使用模版了﹔过年过节时,妈妈用「粿印」来做出一整笼的红龟粿,这时阿妈就在使用模版了。上述这些印章及粿印皆是日常生活中我们所常见的模版。甚至我们走在沙滩上时,我们的脚掌就是个模版,不断地造出脚印﹗上述的印章、粿印等通常是不需调整的,只需重复使用它即可了。不过,还有一种更具弹性的模版,它是可调整或抽换模版中的某些组件,例如邮局服务员使用的「邮戳」,其每天皆得抽换其日期数字,才能不断重复使用之﹔再如我们古代四大发明之一的活字版,也是可调整和抽换的活动模版。活动模版的好处有:

● 能不断重复使用 -- 例如使用活字版来复制成千上万份的报纸﹔邮差每天盖无数个戳印。

● 能弹性调整 -- 例如活字版可随时修正、调整版面、抽换字体,以应付外在环境的随时变化﹔再如邮戳能抽换其日期数字后,所以能天天使用了。

                  

       在软件方面,也有各式各样的模版,例如您已非常熟悉的「类」就是个典型的模版,可制造出一序列结构类似但内容不同的对象(又称物件)。

             

      由于类已定义好数据项及函数,所以每个对象的数据项及函数皆相同,只有其数据值不同。就如同每个红龟粿的形状相同,但其实际原料则不同。因之,类就是对象之样模版,或称为对像模版(Object Template) ,用来制造一序列类似的对象。以此类推,可想想:类之模版是什么呢﹖在Java里,提供了类模版(Class Template)之观念,其可用来制造一序列结构类似的类。

         

      类模版是可调整的模版,经由调整就可制造出各式各样的相似的类,然后再由类来制造一序列相似的对象。类模版将是本章所要介绍的重点。不过在介绍类模版之前,将先介绍较基本的函数模版──能用来制造一序列相似函数的活动模版。

 

3. 类(Class)模版

    如果类之间只是数据型态不同而已,就可导出类模版。例如: 

3.1  Java范例

//--- Ex01 in Java ---

class DoubleData {   

       private Double value;   

       DoubleData(Double v) {  value = v;  }

       public Double Value() {  return value;  }

 }

class StringData {   

      private String value;   

      StringData(String v)   {  value = v;  }

      public String Value()  {  return value;  }

 }

public class JMain {

      public static void main(String[] args) {

                     DoubleData price = new DoubleData(78000.25);

                     StringData hello = new StringData("good morning");

                     System.out.println( price.Value() + ", " + hello.Value());

  }}

       这两类的数据项及函数皆相同,只是数据型态不同而已。此时就是类模版的适用场合﹗导出类模版的步骤是:

Step 1: 找出相异点,如下:

           

 

Step 2: 拿个较通用之名称来取代DoubleData及 StringData类名称,做为模版名称。例如,Data是个适当的名称,其意义上包括了DoubleData及StringData。

Step 3: 以T 来代替Double及String型态名称。于是,得到类模版:Data<T>,兹以Java表达如下:

 

//--- Ex02 in Java ---

class Data<T> {   

         private T value;   

         Data(T v) {  value = v;  }

         public T Value() {  return value;  }

   }

public class JMain {

        public static void main(String[] args) {

        Data<Double> price = new Data<Double>(87000.25);

        Data<String> hello = new Data<String>("good morning");

        Data<Long> distance = new Data<Long>(6553500L);

        System.out.println( price.Value() + ", " + hello.Value() + ", " + distance.Value());

  }}

 

当编译到指令:

            Data<Double> price = new Data<Double>(87000.25);

时,就拿 Double 来代换模版的参数──T ,于是诞生了新类: 

class Data<Double> {   

          private Double value;   

          Data(Double v) {

                   value = v;

            }

          public Double Value() {

                 return value; 

       }

   }

同样地,编译到指令:

          Data<String> hello = new Data<String>("good morning"); 

时,就拿String来代换模版参数──T,于是诞生了Data<String>新类。因之,此程序编译之后,程序中含有3个类:Data<Double>、Data<String>和Data<Long>。从上所述,可归纳如下:

         ◎ 从实际类中,区分出其相异点。

         ◎ 如果类内容大同小异,只是数据型态和类名称不同时,宜用类模版。

         ◎ 一旦导出类模版,可依参数型态来产生各式各样之类。

 

3.2  C++范例

     C++类模版的最简单格式是:

              template <char  型态代称> 

              class 类名称

                     { ... } 

 

也常写成一行如下:

           template <char 型态代称>  class类名称

                      { ... } 

 

如此,就定义了类模版。例如: 

//--- Ex03 in C++ ---

template <class T, int dv>

class Number {

          T value;

      public:

          Number( T v = dv ) : value(v)  {}

          T Value()    { return value; }

   };

 

兹写个主程序:

 

//--- Ex04 in C++ ---

#include <iostream.h>

#include  "cx10-01.h"

int main(){

         const int k=10;

         Number<int, 30>   a, b(10);

         Number<int, 5*10> c;

         Number<int, 5*k>  d;

         cout << a.Value() << ", " << b.Value() << endl;

         return(0);

 }

 

其中,指令:

          template <class T,  int dv>  

                   ﹉﹉﹉    ﹉﹉

                    ↑        ↑

                    │        └─(说明:dv可代表int 常数值)

                    └─(说明:T 可代表任何型态)

 

编译时,看到Number<int, 30> 就会产生一个类:

 

     class Number<int,  30> 

                  ﹉﹉  ﹉

            {     │    ╰────╮

                  ↓             │

                  int value;     ↓

               public:           ﹍

                 Number( int v = 30 ) : value(v)  {} 

                 int Value()  { return value; }

            };

接下来,看到Number<int, 5*10> 时,会诞生个类:

            class Number<int, 50> 

                     { ...... } 

 

       最后,看到Number<int, 5*k>时,其5*k 值为50,此时Number<int, 50> 已存在了,就不再诞生类,只使用现成的 Number<int, 50>就行了。[歡迎光臨 高煥堂 網頁: http://www.cnblogs.com/myEIT/ ]

 

4.  Android框架里的模版范例

      框架设计者通常撰写一些抽象的基类(Super class)和接口(Interface),它们就成为框架的主要内涵了。基于此框架,AP开发者就能撰写子类(Subclass)来继承框架里的基类或使用其接口。上述的框架与AP之间的最常见结构。然而,一个完整的框架,常需要其它花招或更具巧思的结构。例如,模版就是一项不可或缺的结构。其必要性在于:

  • 大家都知道AP开发者实现框架里所定的接口。意味着,框架开发者订定接口给AP开发者来使用。
  • 然而,AP开发者也能订定接口来给框架开发者来使用呀! 只是AP开发在后,框架开发在先,框架开发者又如何使用后来才创建的接口呢? 答案就是:擅用模版。

      由于框架设计在先,于是使用T来代表未知的接口,例如Android框架里的BnInterface<T>和BpInterface<T>模版。应用程序(AP)撰写在后,于是定义了接口,例如ISQRS,然后取代T,而成为BnInterface<ISQRS>和BpInterface<ISQRS>。详细实作如下:

 

4.1  框架里的模版写法: 以Android为例

    以Android框架为例,框架里已经设计了两个模版类,如下:

 

template<typename INTERFACE>

class BnInterface : public INTERFACE, public BBinder

{

public:

    virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);

    virtual String16       getInterfaceDescriptor() const; 

protected:

    virtual IBinder*      onAsBinder();

};

 

// ----------------------------------------------------------------------

 

template<typename INTERFACE>

class BpInterface : public INTERFACE, public BpRefBase

{

public:

           BpInterface(const sp<IBinder>& remote); 

protected:

    virtual IBinder*  onAsBinder();

};

 

4.2  AP里的模版用法: 以Android为例

    基于上述Android框架里的两个模版,AP开发者就能使用之。其使用方法是:

  • 在AP里定义接口,如下: 

// ISQRS.h

#include <utils/RefBase.h>

#include <utils/IInterface.h>

#include <utils/Parcel.h>

#ifndef ANDROID_MISOO_ISQRS_SERVICE_H

#define ANDROID_MISOO_ISQRS_SERVICE_H

 

namespace android {

class ISQRS: public IInterface

public:

    DECLARE_META_INTERFACE(SQRS);

    virtual int square(const int& n) = 0;

};

  •  以接口来去取代模版< >里的T,如下: 

class BpSQRS: public BpInterface<ISQRS>{

public:

    BpSQRS(const sp<IBinder>& impl): BpInterface<ISQRS>(impl){}

    virtual int square(const int& n);

};

}; // namespace android

#endif 

 

5. 结语

      接口就是一种纯抽象(pure abstract)的基类,而实作(Implement)接口就是继承纯抽象(pure abstract)的基类。BpInterface<ISQRS>意味着,框架开发者来实现AP开发者所订定的接口。也就是框架里的模版类继承了AP里的接口类。一般的继承机制,让AP的类可继承框架里的基类。而样板类机制则相反,让框架的类可继承AP里的基类。于是,具有了双向的继承机制。这是杰出框架设计者,所不可或缺的两把刷子。◆  

[Go Back]

 

发表于 2013-11-11 07:28  高煥堂.EIT  阅读(179)  评论(0)    收藏  举报
 
刷新页面返回顶部