精华内容
下载资源
问答
  • 接口定义及使用

    万次阅读 多人点赞 2018-08-07 17:50:28
    一、接口的基本定义 如果一个类之中只是由抽象方法和全局常量所组成的,那么在这种情况下不会将其定义为一个抽象类,而只会将其...范例:定义接口 interface A {// 定义了接口 public static final String MSG ...

    一、接口的基本定义

    如果一个类之中只是由抽象方法和全局常量所组成的,那么在这种情况下不会将其定义为一个抽象类,而只会将其定义为接口,所以所谓的接口严格来讲就属于一个特殊的类,而且这个类里面只有抽象方法与全局常量。

    要定义一个接口使用interface关键字完成。

    范例:定义接口

    interface A {// 定义了接口
    	public static final String MSG = "Hello";// 全局常量
    	// 抽象方法
    
    	public abstract void print();
    }

    由于接口里面存在有抽象方法,所以接口对象不可能直接使用关键字new进行实例化的操作,所以接口的使用原则如下:

    · 接口必须要有子类,但是此时一个子类可以使用implements关键字实现多个接口;

    · 接口的子类(如果不是抽象类),必须要覆写接口中的全部抽象方法;

    · 接口的对象可以利用子类对象的向上转型进行实例化操作。

     

    范例:实现接口

    interface A {// 定义了接口
    	public static final String MSG = "Hello";// 全局常量
    	// 抽象方法
    
    	public abstract void print();
    }
    
    interface B {
    	public abstract void get();
    }
    
    class X implements A, B {// X类实现A和B两个接口
    
    	@Override
    	public void get() {
    		System.out.println("B接口的抽象方法!");
    	}
    
    	@Override
    	public void print() {
    		System.out.println("A接口的抽象方法!");
    	}
    }
    
    public class Demo {
    	public static void main(String args[]) {
    		X x = new X();
    		A a = x;// 向上转型
    		B b = x;// 向上转型
    		a.print();
    		b.get();
    	}
    }

    以上的代码实例化了X类对象。由于现在X是A和B的子类,所以X类的对象可以变成A接口或者B接口类的对象。

    public class Demo {
    	public static void main(String args[]) {
    		A a = new X();
    		B b = (B) a;
    		b.get();
    		System.out.println(a instanceof A);
    		System.out.println(a instanceof B);
    	}
    }

    在定义结构上来讲,A和B接口没有任何的直接联系,但是这两个接口却同时拥有一个子类:X子类,千万不要被类型和名称所迷惑。因为最终实例化的是X子类,而这个子类属于B类的对象,所以以上的代码成立。只不过从代码的编写上来讲并不是很好。

     

    但是要知道一点,对于子类而言,除了接口之外,还可能会去继承抽象类,所以说一个子类既要继承抽象类又要去实现接口的话,那么请先使用extends继承,而后再使用implements实现。

    interface A {// 定义了接口
    	public static final String MSG = "Hello";// 全局常量
    	// 抽象方法
    
    	public abstract void print();
    }
    
    interface B {
    	public abstract void get();
    }
    
    abstract class C {
    	public abstract void change();
    }
    
    class X extends C implements A, B {// X类实现A和B两个接口
    
    	@Override
    	public void get() {
    		System.out.println("B接口的抽象方法!");
    	}
    
    	@Override
    	public void print() {
    		System.out.println("A接口的抽象方法!");
    	}
    
    	@Override
    	public void change() {
    		System.out.println("C类的抽象方法!");
    
    	}
    }

    对接口而言,发现里面的组成就是抽象方法和全局常量,所以很多的时候也有一些人为了省略编写,可以不用写上abstract或public static final,并且在方法上是否编写public结果都是一样的,因为在接口里面只能够使用一种访问权限——public。以下两个接口的定义效果是完全相同的:

    interface A {

    public static final String MSG = "hello";

    public abstract void fun();

    }

    interface A {

    String MSG = "hello";

    void fun();

    }

    在接口里面没有写上public,其最终的访问权限也是public,绝对不是default。为了防止某些不熟悉语法的开发者出现错误,所以强烈建议在接口定义方法的时候一定要写上public。

    interface A {
    	String MSG = "hello";
    	public void fun();
    }

    对于接口的组成,99%的情况下都是以抽象方法为主,很少有接口只是单纯的去定义常量。

     

    一个抽象类可以去定义一个抽象类,但是反过来,一个接口却可以使用extends关键字同时继承多个接口(但是不能继承抽象类)。

    范例:观察接口的多继承

    interface A {
    	public void funA();
    }
    interface B{
    	public void funB();
    }
    //C接口同时继承了A和B两个父接口
    interface C extends A,B{//此处使用的是extends
    	public void funC();
    }
    class X implements C{
    	@Override
    	public void funA() {}
    	@Override
    	public void funB() {}
    	@Override
    	public void funC() {}
    
    }

    从继承关系上讲抽象类的限制要比接口多很多:

    · 一个抽象类只能够继承一个抽象的父类,而接口没有这个限制;

    · 一个子类只能够继承一个抽象类,而却可以实现多个接口。

    在Java里面,接口的主要功能是解决单继承局限问题。

     

    虽然从接口本身的概念来讲只能够由抽象方法和全局变量组成,但是所有的内部结构是不受到这些要求限制的,也就是说:在接口里面可以定义普通内部类、抽象内部类、内部接口。

    范例:在接口里定义抽象类

    interface A {
    	public void funA();
    	abstract class B {
    		public abstract void funB();
    	}
    }
    class X implements A {// X实现了A接口
    	public void funA() {
    		System.out.println("Hello");
    	}
    	class Y extends B {// 内部抽象类的子类
    		@Override
    		public void funB() {
    		}
    	}
    }

    范例:在一个接口内部如果使用了static去定义一个内部接口表示是一个外部接口。

    interface A {
    	public void funA();
    	static interface B {// 外部接口
    		public void funB();
    	}
    }
    class X implements A.B {
    	@Override
    	public void funB() {
    	}
    }

    大部分情况,只要求清楚内部接口的定义即可。

    先期总结:接口在实际的开发之中有三大核心作用:

    · 定义不同层之间的操作标准;

    · 表示一种操作的能力;

    · 表示将服务器端的远程方法视图暴露给客户端。


    二、接口的实际应用——标准定义

    电脑上可以使用U盘、Mp3、打印机,这些设备都是连接到USB设备上的。

    所有的代码如果要进行开发,一定要首先开发出USB接口标准,因为有了标准后,电脑才可以去使用这些标准,设备厂商才可以设计USB设备。

    范例:定义USB标准

    //标准可以连接不同层的操作类
    interface USB{//定义标准一定就是接口
    	public void start();
    	public void stop();
    }

    范例:定义电脑

    class Computer{
    	public void plugin(USB usb){//插入
    		usb.start();//固定操作
    		usb.stop();//固定操作
    	}
    }

    不管以后会有多少个设备,只要它是USB标准的实现子类,就都可以在电脑上使用。

    范例:定义U盘

    class Flash implements USB{
    	@Override
    	public void start() {
    		System.out.println("U盘开始使用");
    	}
    	@Override
    	public void stop() {
    		System.out.println("U盘停止使用");
    	}
    }

    范例:定义打印机

    class Print implements USB{
    	@Override
    	public void start() {
    		System.out.println("打印机开始使用");
    	}
    	@Override
    	public void stop() {
    		System.out.println("打印机停止使用");
    	}
    }

    按照这样的方式,准备出几万个子类都可以,并且这几万个子类都可以在电脑的plugin()方法上使用。

    public class Demo {
    	public static void main(String args[]) {
    		Computer com = new Computer();
    		com.plugin(new Flash());
    		com.plugin(new Print());
    	}
    }

    此时可以很好的描述出现实的关系。

    在现实的生活之中,标准的概念随处可见,而在程序里面标准就是用接口来定义的。


    三、接口的应用——工厂设计模式(Factory)

    下面首先来观察一段程序代码:

    interface Fruit {
    	public void eat();
    }
    
    class Apple implements Fruit {
    
    	@Override
    	public void eat() {
    		System.out.println("吃苹果");
    	}
    }
    
    public class Demo {
    	public static void main(String args[]) {
    		Fruit f = new Apple();
    		f.eat();
    	}
    }

    以上的程序可以通过主方法得到Fruit接口对象,但是有没有一些问题呢?

    如果要想确认一个代码是否真的好,有这么几个标准:

    · 客户端调用简单,不需要关注具体细节;

    · 客户端之外的代码修改,不影响用户的使用,即:用户不用去担心代码是否变更。

    本次的程序没有任何的语法错误,但是关键的问题就出在关键字“new”上。一个接口不可能只有一个子类,所以对于Fruit也有可能产生多个子类对象。

    class Orange implements Fruit {
    
    	@Override
    	public void eat() {
    		System.out.println("吃橘子");
    	}
    }

    现在的客户端上要想得到这新的子类对象,需要修改代码,修改为:

    public class Demo {
    	public static void main(String args[]) {
    		Fruit f = new Orange();
    		f.eat();
    	}
    }

    发现如果现在直接在客户端上产生了实例化对象,那么每一次要想更换对象,都需要修改客户端上的执行代码,这样的做法明显是不好的。

    在整个的代码过程之中,我们最需要关心的是如何取得一个Fruit接口对象,而后进行方法的调用,至于说这个接口对象是被谁实例化的,那不是客户端的工作。

    所以经过分析发现,最大的问题就在于关键字new,而这一问题就可以理解为耦合度太高。耦合度太高的直接问题是代码不方便维护,就相当于A一直要与B绑定在一起。可以完全参考Java虚拟机的设计思想:

    · 程序——>JVM——>适应不同的操作系统(A——>C——>B);

    范例:增加一个过渡

    class Factory {
    	public static Fruit getInstance(String className) {
    		if ("apple".equals(className)) {
    			return new Apple();
    		} else if ("orange".equals(className)) {
    			return new Orange();
    		} else {
    			return null;
    		}
    	}
    }
    
    public class Demo {
    	public static void main(String args[]) {
    		Fruit f = Factory.getInstance("apple");
    		f.eat();
    	}
    }

    现在的客户端不会看见具体的子类,因为所有的接口对象都是通过Factory类取得的,如果日后要扩充新的子类对象,则只需要修改Factory类即可,客户端的调用不会发生变化。

    扩展题目:请编写一个Factory程序。(以上答案)


    四、接口的应用——代理设计模式(Proxy)

    范例:程序(皇帝宠幸妃子)

    interface Subject {// 整个操作的核心主题
    	public void make();
    }
    
    class RealSubject implements Subject {
    	@Override
    	public void make() {
    		System.out.println("过程……");
    	}
    }
    
    class ProxySubject implements Subject {
    	private Subject subject;
    
    	// 要接收一个真实主题的操作对象
    	public ProxySubject(Subject subject) {
    		this.subject = subject;
    	}
    
    	public void prepare() {
    		System.out.println("准备……");
    	}
    
    	@Override
    	public void make() {
    		this.prepare();
    		this.subject.make();
    		this.destory();
    	}
    
    	public void destory() {
    		System.out.println("销毁");
    	}
    }
    
    public class Demo {
    	public static void main(String args[]) {
    		Subject sub = new ProxySubject(new RealSubject());
    		sub.make();// 调用的是代理主题的操作
    	}
    }

    代理设计模式的核心精髓就在于有一个主题操作接口(可能有多种方法),核心业务主题只完成核心功能,例如:吃饭,而代理主题负责完成所有与核心主题有关的辅助性操作。

    扩展题目:请编写一个Proxy程序。(以上答案)


    五、抽象类与接口的区别

    抽象类和接口在使用上是非常相似的,所以很多人很乐意去解释两者的区别。

    No

    区别

    抽象类

    接口

    1

    关键字

    Abstract class

    Interface class

    2

    组成

    构造方法、抽象方法、普通方法、static方法、常量、变量

    抽象方法、全局常量

    3

    子类使用

    class 子类 extends 抽象类

    class 子类 implements 接口,接口,……

    4

    关系

    可以实现多可接口

    不能够继承抽象类,却可以继承多个父接口

    5

    权限

    各种权限

    public

    6

    限制

    单继承局限

    没有单继承局限

    7

    子类

    抽象类和接口都必须有子类,子类必须要覆写全部的抽象方法

    8

    实例化对象

    依靠子类对象的向上转型进行对象的实例化。

    经过比较可以发现,抽象类支持的功能绝对要比接口更多,但是只有一点不好,那就是单继承局限,这重要的一点就掩盖了所有抽象类的优点,即:当抽象类和接口都可以使用的时候,优先考虑接口。

    一个参考(50%):

    · 在进行某些公共操作的时候一定要定义出接口;

    · 有了接口就需要利用子类完善方法;

    · 如果自己写的接口,那么绝对不要去使用关键字new直接实例化接口子类,使用工厂类完成。

     

    总结:

    1. 接口与抽象类定义的不同;
    2. 接口作为标准用于解耦合以及不同层之间的连接桥梁;

     

    展开全文
  • 初学TypeScript之接口定义

    万次阅读 2019-05-06 09:19:37
    前面讲了如何使用TypeScript和TypeScript的数据类型有哪些,这章就讲解TypeScript的接口。 如果不知道如何写TypeScript的朋友或者不知道TypeScript的数据类型有哪些的朋友可以转至 TypeScript的使用以及数据类型...

    TypeScript入门(2)

    前面讲了如何使用TypeScript和TypeScript的数据类型有哪些,这一章就讲解TypeScript的接口。
    如果不知道如何写TypeScript的朋友或者不知道TypeScript的数据类型有哪些的朋友可以转至 TypeScript的使用以及数据类型详解 处观看。

    接口:

    简介:
    TypeScript的核心原则是对值所具有的结构进行类型检查。在TypeScript里,接口的作用就是为这些类型命名和你的代码或第三方代码定义锲约。简单的来说就是每一次定义或者输出的时候都要定义类型。
    小demo让你更加的了解TypeScript:

    function test(labelObj: { label: string }) {
    	console.log(labelObj);
    }
    
    let myObj = { size: 10, label: 'size 10 Object'};
    test(myObj);
    

    类型检查器会查看test的调用。test有一个参数,并要求这个这个对象参数有一个名为label类型为string的属性。
    改写上面的demo,让你更了解TypeScript的接口:

    interface LabelValue {
    	label: string;
    }
    
    function test(labelObj: LabelValue) {
    	console.log(labelObj.label);
    }
    
    let myObj = {size: 10, label: 'Size 10 Object'};
    test(myObj);
    

    labelValue接口就好比一个名字,用来描述上面例子里的要求。意思是与上面的例子意思一样的。不一样的是我们在这里并不能像在其他语言里一样,说传给test的对象实现了这个接口。我们只会去关注值的外形。只要传入的对象满足上面提到的必要条件,那么就是被允许的。而且类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以。
    可选属性:
    接口里的属性不全都是必须的。有些是只在某些条件下存在,或者根本不存在。可选属性在应用“option bags”模式时很常用,即给函数传入的参数对象中只有部分属性赋值了。
    下面是应用了“option bags”的demo:

    interface SquareConfig {
    	color?: string;
    	width?: number;
    }
    
    function createSquare(config: SquareConfig): {color: string; area: number} {
    	let newSquare = {color: "white", area: 100};
    	if (config.color) {
    		newSquare.color = config.color;
    	}
    	if (config.width) {
    		newSquare.area = config.width * config.width;
    	}
    	return newSquare;
    }
    
    let mySquare = createSquare({color: "black"});
    

    带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个“?”符号。
    可选属性的好处之一是可以对可能存在的属性进行预定义,好处之二是可以捕获引用了不存在的属性时的错误。比如,我们故意讲createSquare里的color属性名拼错,就会得到一个错误提示:

    interface SquareConfig {
      color?: string;
      width?: number;
    }
    
    function createSquare(config: SquareConfig): { color: string; area: number } {
      let newSquare = {color: "white", area: 100};
      if (config.clor) {
        // Error: Property 'clor' does not exist on type 'SquareConfig'
        newSquare.color = config.clor;
      }
      if (config.width) {
        newSquare.area = config.width * config.width;
      }
      return newSquare;
    }
    
    let mySquare = createSquare({color: "black"});
    

    只读属性:
    一些对象属性只能在对象刚刚创建的时候修改其值。你可以在属性名前用readonly来指定只读属性:

    interface Point {
    	readonly x: number;
    	readonly y: number;
    }
    

    你可以通过赋予一个对象字面量来构造一个Point。赋值后,x和y再也不能被改变了。

    let p1: Point = { x: 10, y: 20 };
    p1.x = 12;		//error!
    

    TypeScript具有 ReadonlyArray<T> 类型,它与Array<T> 相似,只是把所有可变方法去掉了,因此可以确保数据创建后再也不能被修改:

    let a:number[] = [1,2,3,4];
    let ro: ReadonlyArray<number> = a;
    ro[0] = 12;   //error!
    ro.push(5);		//error!
    ro.length = 50;		//error!
    a = ro;		//error!
    

    上面代码的最后一行,大家可以看到就算把整个ReadonlyArray赋值到一个普通数组也是不可以的。但是你可以用 类型断言 重写:

    a = ro as number[];
    
    readonly VS const

    最简单判断该用readonly还是const的方法是看要把它做为变量使用还是作为一个属性。作为变量使用的话用const,若作为属性则使用readonly。

    额外的属性检查:

    我们在第一个例子里面使用了接口,TypeScript让我们传入 { size: number; label: string; }到仅期望得到{label: string; }的函数里。我们已经学过了可选属性。并且知道他们在“option bags”模式里很有用。
    然而,天真地将这俩者结合的话就会像在JavaScript里那样搬起石头砸自己的脚。比如,拿createSquare例子来说:

    interface SquareConfig {
    	color?: string;
    	width?: number;
    }
    function createSquare(config: SquereConfig): { color: string; area: number } {
    	//...
    }
    let mySquare = createSquare({ colour: "red", width: 100});
    

    注意传入createSquare的参数拼写为colour而不是color。在JavaScript里,这会默默地失败。
    你可能会争辩这个程序已经正确地类型化了,因为width属性是兼容的,不存在color属性,而且额外的colour属性是无意义的。
    然而,TypeScript会认为这段代码可能存在bug。对象字面量会被特殊对待而且会经过额外属性检查,当将它们赋值给变量或作为参数传递的时候。如果一个对象字面量存在任何“目标类型”不包含的属性时,你会得到一个错误。

    //error: 'colour' not expected in type 'SquareConfig'
    let mySquare = createSquare({ colour: 'red', width: 100 });
    

    绕开这些检查非常简单。最简单的方法是使用类型断言:

    let mySquare = createSquare({ width: 100, opacity: 0.5} as SquareConfig);
    

    然而最佳的方式是能够添加一个字符串索引签名,前提是你能够确定这个对象可能具有某些做为特殊用途使用的额外属性。如果SquareConfig带有上面定义的类型的color和width属性,并且还会带有任意数量的其他属性,那么我们可以这么定义它:

    interface SquareConfig {
    	color?: string;
    	width?: number;
    	[propName: string]: any;
    }
    

    待会会讲索引签名,但在这我们要表示的是SquareConfig可以有任意数量的属性,并且只要它们不是color和width,那么就无所谓它们的类型是什么。

    还有一种跳过这些检查的方式,这可能会让你感到惊讶,它就是将这个对象赋值给另一个变量:因为squareOptions不会经过额外的属性检查,所以编译器不会报错。

    let squareOptions = { colour: "red", width: 100};
    let mySquare = createSquare(squareOptions);
    

    要留意,在像上面一样简单代码里,你可能不应该去绕开这些检查。对于包含方法和内部状态的复杂对象字面量来讲,你可能需要使用这些技巧,但是大部额外属性检查错误是真正的bug。 就是说你遇到了额外类型检查出的错误,比如“option bags”,你应该去审查一下你的类型声明。 在这里,如果支持传入 color或colour属性到createSquare,你应该修改SquareConfig定义来体现出这一点。
    函数类型:
    接口能够描述JavaScript中对象拥有的各种各样的外形。除了描述带有属性的普通对象外,接口也可以描述函数类型。
    为了使接口表示函数类型,我们需要给接口定义一个调用签名。它就像是一个只有参数列表和返回值类型的函数定义。参数列表里的每个参数都需要有名字和类型。

    interface SearchFunc {
    	(source: string, subString: string): boolean;
    }
    

    这样定义后,我们可以像使用其他接口一样使用这个函数类型的接口。下例展示了如何创建一个函数类型的变量,并将一个同类型的函数赋值给这个变量。

    let mySearch: SearchFunc;
    mySearch = function(source: string, subString: string) {
    	let result = source.search(subString);
    	return result > -1;
    }
    

    对于函数类型的检查来说,函数的参数名不需要与接口里定义的名字相匹配。比如,我们使用下面的代码重写上面的例子:

    let mySearch: SearchFunc;
    mySearch = function(src: string, sub: string): boolean {
    	let result = src.search(sub);
    	return result > -1;
    }
    

    函数的参数会逐个进行检查,要求对应位置上的参数类型是兼容的。如果你不想指定类型,TypeScript的类型系统会推断出参数类型,因为函数之间赋值给了SearchFunc类型变量。函数的返回值类型是通过其返回值推断出来的(此例是false和true)。如果让这个函数返回数字或字符串,类型检查器会警告我们函数的返回值类型与SearchFunc接口中的定义不匹配。

    let mySearch: SearchFunc;
    mySearch = function(src, sub) {
    	let result = src.search(sub);
    	return result > -1;
    }
    

    可索引的类型:
    与使用接口描述函数类型差不多,我们定义了StringArray接口,它具有索引签名。这个索引签名表示了当用number去索引StringArray时会得到string类型的返回值。
    TypeScript支持俩种索引签名:字符串和数字。可以同时使用俩种类型的索引,但是数字索引的返回值必须是字符串索引返回值类型的子类型。这是因为当使用number来索引时,JavaScript会将它转换成string然后再去索引对象。也就是说用100(一个number)去索引等同于使用“100”(一个string)去索引,因此俩者需要保持一致。

    class Animal {
    	name: string;
    }
    class Dog extends Animal {
    	breed: string;
    }
    
    //错误:使用数字型的字符串索引,有时会得到完全不同的Animal!
    interface NotOkay {
    	[x: number]: Animal;
    	[x: string]: Dog;
    }
    

    字符串索引签名能够很好的描述dictionary模式,并且它们也会确保所有属性与其返回值类型想匹配。因为字符串索引声名了obj.property和obj[“property”]俩种形式都可以。下面的例子里,name的类型与字符串索引类型不匹配,所以类型检查器给出一个错误提示:

    interface NumberDictionary {
    	[index: string]: number;
    	length: number;		//可以,length是number类型
    	name: string;		//错误,'name'的类型与索引类型返回值的类型不匹配
    }
    

    最后,你可以将索引签名设置为只读,这样就防止了给索引赋值:

    interface ReadonlyStringArray {
    	readonly [index: number]: string;
    }
    let myArray: ReadonlyStringArray = ["Alice","Bob"];
    myArray[2] = "Mallory";		//error!
    

    你不能设置myArray[2],因为索引签名是只读的。

    类类型:
    实现接口:
    与C#或java里接口的基本作用一样,TypeScript也能够用它来明确的强制一个类去符合某种契约。

    interface ClockInterface {
    	currentTime: Date;
    }
    
    class Clock implements ClockInterface {
    	currentTime: Date;
    	constructor(h: number, m: number) {}
    }
    

    你也可以在接口中描述一个方法,在类里实现它,如同下面的setTime方法一样:

    interface ClockInterface {
    	currentTime: Date;
    	setTime(d: Date);
    }
    
    class Clock implements ClockInterface {
    	currentTime: Date;
    	setTime(d: Date) {
    		this.currentTime = d;
    	}
    	constructor(h: number, m: number) {}
    }
    

    接口描述了类的公共部分,而不是公共和私有俩部分。它不会帮你检查类是否具有某些私有成员。
    类静态部分与实例部分的区别:
    当你操作类和接口的时候,你要知道类是具有俩个类型的:静态部分的类型和实例的类型。你会注意到,当你用构造器签名去定义一个接口并视图定义一个类去实现这个接口时会得到一个错误:

    interface ClockConstructor {
    	new (hour: number, minute: number);
    }
    class Clock implements ClockConstructor {
    	currentTime: Date;
    	constructor(h: number, m: number) {}
    }
    

    这里因为当一个类实现了一个接口时,只对其实例部分进行类型检查。constructor存在于类的静态部分,所以不在检查的范围内。
    因此,我们应该直接操作类的静态部分。看下面的demo,我们定义了俩个接口,ClockConstructor为构造函数所用和ClockInterface为实例方法所用。为了方便我们定义一个构造函数createClock,它用传入的类型创建实例。

    interface ClockConstructor {
    	new (hour: number, minute: number): ClockInterface;
    }
    interface ClockInterface {
    	tick();
    }
    
    function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    	return new ctor(hour, minute);
    }
    
    class DigitalClock implements ClockInterface {
    	constructor(h: number, m: number) {}
    	tick() {
    		console.log('beep beep');
    	}
    }
    
    class AnalogClock implements ClockInterface {
    	constructor(h: number, m: number) {}
    	tick() {
    		console.log('tick tock');
    	}
    }
    
    let digital = createClock(DigitalClock, 12, 17);
    let analog = createClock(AnalogClock, 7, 32);
    

    因为createClock的第一个参数是ClockConstructor类型,在createClock(AnalogClock, 7, 32)里,会检查AnalogClock是否符合构造函数签名。
    继承接口:
    和类一样,接口也可以相互继承。这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。

    interface Shape {
    	color: string;
    }
    interface Square extends Shape {
    	sideLength: number;
    }
    let square = <Square>{};
    square.color = 'blue';
    square.sideLength = 10;
    

    一个接口可以继承多个接口,创建出多个接口的合成接口。

    interface Shape {
    	color: string;
    }
    interface PenStroke {
    	penWidth: number;
    }
    interface Square extends Shape, PenStroke {
    	sideLength: number;
    }
    let square = <Square>{};
    square.color = 'blue';
    square.sideLength = 10;
    square.penWidth = 5.0;
    

    混合类型:
    先前我们提过,接口能够描述JavaScript里丰富的类型。因为JavaScript其动态灵活的特点,有时你会希望一个对象可以同时具有上面提到的多种类型。
    一个例子就是,一个对象可以同时做为函数和对象使用,并带有额外的属性。

    interface Counter {
    	(start: number): string;
    	interval: number;
    	reset(): void;
    }
    function getCounter(): Counter {
    	let counter = <Counter>function (start: number) {};
    	counter.interval = 123;
    	counter.reset = function () {};
    	return counter;
    }
    let c = getCounter();
    c(10);
    c.reset();
    c.interval = 5.0;
    

    在使用JavaScript第三方库的时候,你可能需要像上面那样去完整地定义类型。
    接口继承类:
    当接口继承了一个类类型时,它会继承类的成员但不包括其实现。就好像接口声名了所有类中存在的成员,但并没有提供具体实现一样。接口同样会继承到类的private和protected成员。这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)。
    当你有一个庞大的继承结构时这很有用,但要指出的是你的代码只在子类拥有特定属性时起作用。这个子类除了继承至基类外与基类没有任何关系。例:

    class Control {
    	private state: any;
    }
    interface SelectableControl extends Control {
    	select(): void;
    }
    class Button extends Control implements SelectableControl {
    	select(){}
    }
    class TextBox extends Control {
    	select() {}
    }
    //错误:“Image”类型确实“state”属性。
    class Image implements SelectableControl {
    	select() {}
    }
    class Location {
    
    }
    

    在上面的例子里,SelectableControl包含了Control的所有成员,包括私有成员state。因为state是私有成员,所以只能够是Control的子类们才能实现SelectableControl接口。因为只有Control的子类才能够拥有一个声名于Control的私有成员state,这对私有成员的兼容性是必需的。
    在Control类内部,是允许通过SelectableControl的实例来访问私有成员state的。实际上,SelectableControl接口和拥有select方法的Control类是一样的。Button和TextBox类是SelectableControl的子类(因为它们都继承自Control并有select方法),但Image和Location类并不是这样的。
    下一章节我们来介绍类的概念。学习TypeScript之类的概念

    展开全文
  • IDL接口定义语言教程

    千次阅读 2013-07-02 11:36:57
    也叫“接口描述语言”(Interface Description Language),是一个描述软件组件接口的语言规范。 IDL用中立语言的方式进行描述,能使软件组件(不同语言编写的)间相互通信。 IDL通常用于RPC(Remote Procedure Call...


    IDL接口定义语言

     

    也叫“接口描述语言”(Interface Description Language),是一个描述软件组件接口的语言规范。 IDL用中立语言的方式进行描述,能使软件组件(不同语言编写的)间相互通信。 IDL通常用于RPC(Remote Procedure Call,远程过程调用)软件。 IDL提供了一个“桥”来连接不同的系统。

     

    基于IDL的软件系统包括:

    Sun公司的ONCRPC,

    The Open Group的DistributedComputing Environment(分布式计算环境),

    IBM的SystemObject Model(系统对象模型),

    OMG组织的CORBA,

    Facebook公司的Thrift,

    用于WebService的WSDL。

     

    IDL Specification Language

    类似于其它的接口描述语言,IDL以独立于语言和硬件的方式来定义接口,允许组件间的接口规范采用不同语言编写,通过RPC可以执行在不同的机器上。

    Java IDL把CORBA的能力移植到Java平台,提供了基于标准的互操作能力和连通性。Java IDL使分布式带Web功能的Java应用程序能够透明地调用使用业界标准的OMG IDL的远程网络服务。

    Java IDL技术是基于接口的,定义在CORBA IDL之上,为想使用Java编程语言的CORBA程序员进行编程的。这就是“Business as usual”(照常营业,一切正常)的CORBA编程,支持Java技术,同样也支持C++或COBOL。

    IDL(Interface Definition Language)即接口定义语言,是CORBA规范的一部分,是跨平台开发的基础。IDL提供一套通用的数据类型,并以这些数据类型来定义更为复杂的数据类型。可变化 IDL 基本类型 整数类型 OMG IDL 摒弃int 类型在不同平台上取值范围不同带来的多义性的问题。常数定义常数可以是整数、字符、浮点数、字符串、Boolean、octet 或枚举型,不能是 any 类型或用户定义的类型。OMG IDL数组类型IDL array 和sequence,可以轻易地被映射到实现语言中。序列可以包含所有类型的元素,不管是基本类型还是用户定义的类型。


    OMG IDL文件概述

      从本质上讲,OMG IDL接口定义语言不是作为程序设计语言体现在CORBA体系结构中的,而是用来描述产生对象调用请求的客户对象和服务对象之间的接口的语言。OMG IDL文件描述数据类型和方法框架,而服务对象则为一个指定的对象实现提供上述数据和方法。
      OMG IDL文件描述了服务器提供的服务功能,客户机可以根据该接口文件描述的方法向服务器提出业务请求。在大多数CORBA产品中都提供IDL到相关编程语言的编译器。程序设计人员只需将定义的接口文件输入编译器,设定编译选项后,就可以得到与程序设计语言相关的接口框架文件和辅助文件。

    IDL文件应用过程如图1所示。

     

     

    图1OMG IDL文件编译过程 

    在语法规则方面,类似于C++或Java中关于接口或对象的定义,OMG IDL增加了一些构造方法支持IDL特有的方法调用机制。OMG IDL只是一种说明性的语言,支持C++语法中的常量、类型和方法的声明。采用OMG IDL这样的说明性语言,其目的在于克服特定编程语言在软件系统集成及互操作方面的限制,这正是CORBA的诱人之处,同样也体现出采用CORBA构造分布式应用程序在网络时代的强大生命力。OMG IDL已经为C、C++、Java等主要高级程序设计语言制定了IDL到高级编程语言的映射标准。项目开发人员可以根据需要选择自己最熟悉的编程语言来独立开发基于CORBA的应用,而对软件系统的互操作能力不产生影响。
    OMG IDL的语法规则

    1. OMG IDL文件举例

      module Compute
      { typedef double radius;
      typedef long times;
      interface PI
      { double getResult( in radiusaRadius, in times time); }
      }
      上述接口定义文件主要用于客户端向服务对象提出请求:计算π值。因此,模块中定义了一个方法getResult(),以圆的直径(aRadius)和迭代次数(times)作为该方法的输入参数。

    2. OMG IDL词法规则

      OMG IDL采用ASCII字符集构成接口定义的所有标识符。标识符由字母、数字和下划线的任意组合构成,但第一个字符必须是ASCII字母。IDL认为大写字母和小写字母具有相同的含义,例如anExample和AnExample是相同的。

    与C++和Java类似,采用以“/*”开始,以“*/”结束来注释一段代码,以“//”开始注释从“//”开始直至行尾的所有内容。
      另外,IDL保留了47个关键字,程序设计人员不能将关键字用作变量或方法名。需要注意的是关键字的大小写,例如:
      typedef double context;
      //错误:定义的变量context是关键字
      typedef double CONTEXT;
      //错误:CONTEXT与关键字context冲突

    3. 数据类型

      (1)基本数据类型:OMG IDL基本数据类型包括short、long和相应的无符号(unsigned)类型,表示的字长分别为16、32位。
      (2)浮点数类型:OMG IDL浮点数类型包括float、double和longdouble类型。其中float表示单精度浮点数,double表示双精度浮点数,long double表示扩展的双精度浮点数。
      (3)字符和超大字符类型:OMG IDL定义字符类型char为面向字节的码集中编码的单字节字符; 定义类型wchar为从任意字符集中编码的超大字符。
      (4)逻辑类型:用boolean关键字定义的一个变量,取值只有true和false。
      (5)八进制类型:用octet关键字定义,在网络传输过程中不进行高低位转换的位元序列。

    (6)any数据类型:引入该类型用于表示OMG IDL中任意数据类型。

    4. 常量

      OMG IDL用const关键字声明一个常量,用于模块(module)或接口(interface)中定义保持不变的量,如:
      const double PI = 3.1415926;
      在IDL中,可以定义long、unsigned long、unsigned short、char、boolean、float、double、string类型的常量。

    5. 构造数据类型

      类似于C和C++的语法规则,OMG IDL中构造数据类型包括结构、联合、枚举等形式。如下例:
    (1)结构类型:
      typedef long GoodsNumber;
      struct
      { GoodsNumber number;
      string name;
      float price; }
    (2)联合类型:
      union stockIn switch( short )
      { case 1: stocker : long;
      case 2: goodsName1 : string;
      case 3: goodsName2 : string; }
    (3)枚举类型:
      enum GoodsStatus { GOODS_SALED,GOODS_INSTOCK};

    6. 数组类型

      OMG IDL的数组类型提供了多维定长、统一数据格式的数据存储方式——数组。每一维的长度必须在定义时给定,所有数据单元必须存储相同类型的元素。如下例定义一个长度为20×100的整数数组:
      typedef long aDimension[20][100];

    7.模板(template)类型

      OMG IDL提供两种类型的模板:
    (1) 序列(sequence)类型:
      用该方法定义长度可变的任意数值类型的存储序列,通常在定义时可以指定长度,也可以不指定,如:
      typedef sequence <long,80> aSequence;
      //长度定义为80
      typedef sequence <long>anotherSequence;
      //长度不定
    (2) 字符串(string)序列:
      同样对于字符串序列类型,也有两种定义方式:
      typedef string <80> aName;//长度定义为80
      typedef string anotherName; //长度不定

    8.接口(interface)

      在前几讲中,均提到了CORBA接口,接口作为服务对象功能的详细描述,封装了服务对象提供服务方法的全部信息,客户对象利用该接口获取服务对象的属性、访问服务对象中的方法。
      接口用关键字interface声明,其中包含的属性和方法对所有提出服务请求的客户对象是公开的,如下例:
      interface JobManager
      { readonly attribute stringFirstName;
      attribute string status;
      string QueryJobStatus( in longNumber, out string property); }

     

    CORBA

    CORBA(CommonObject Request Broker Architecture公共对象请求代理体系结构)是由OMG组织制订的一种标准的面向对象应用程序体系规范。或者说CORBA体系结构是对象管理组织(OMG)为解决分布式处理环境(DCE)中,硬件和软件系统的互连而提出的一种解决方案;OMG组织是一个国际性的非盈利组织,其职责是为应用开发提供一个公共框架,制订工业指南和对象管理规范,加快对象技术的发展。
      OMG组织成立后不久就制订了OMA(ObjectManagement Architecture,对象管理体系结构)参考模型,该模型描述了OMG规范所遵循的概念化的基础结构。OMA由对象请求代理ORB、对象服务、公共设施、域接口和应用接口这几个部分组成,其核心部分是对象请求代理ORB(ObjectRequest Broker)。对象服务是为使用和实现对象而提供的基本服务集合;公共设施是向终端用户应用程序提供的一组共享服务接口;域接口是为应用领域服务而提供的接口;应用接口是由开发商提供的产品,用于它们的接口,不属于OMG标准的内容。ORB提供了一种机制,通过这种机制,对象可以透明的发出请求和接收响应。分布的、可以互操作的对象可以利用ORB构造可以互操作的应用。
      CORBA标准由对象管理组织(OMG)设立并进行控制,CORBA定议了一系列API,通信协议,和物件/服务信息模型用于使得异质应用程序能够互相操作,这些应用程序用不同的程序语言编写,运行在不同的平台上。CORBA因此为定义明确的物件提供了平台和位置的透明性,这些物件是分布式计算平台的基础。
      CORBA分布计算技术,是由绝大多数分布计算平台厂商所支持和遵循的系统规范技术,具有模型完整、先进,独立于系统平台和开发语言,被支持程度广泛的特点,已逐渐成为分布计算技术的标准。COBRA标准主要分为3个层次:对象请求代理、公共对象服务和公共设施。最底层是对象请求代理ORB,规定了分布对象的定义(接口)和语言映射,实现对象间的通讯和互操作,是分布对象系统中的"软总线";在ORB之上定义了很多公共服务,可以提供诸如并发服务、名字服务、事务(交易)服务、安全服务等各种各样的服务;最上层的公共设施则定义了组件框架,提供可直接为业务对象使用的服务,规定业务对象有效协作所需的协定规则。
      CORBA(公共对象请求代理架构):这是个和微软com,com+齐名的同类软件技术规范,由OMT提出。
      用于在不同进程(程序)之间,甚至是不同物理机器上的进程(程序)之间通讯。底层技术依靠RPC[远程过程调用]实现。
      面向对象的软件,以数据为中心设计,对象类既具有模块的封装性和类属等特性,还具有继承特性
      ,极大地提高了类的可扩充性和可再用能力。对象类较之于传统软件的功能模块而另具有的优点是:
      (1)易于理解,具有完整的语义特征;
      (2)易于扩充和修改,具有较高的通用性和适应性;
      (3)易于构造组装,具有规范的外部接口。
      开发应用组件必须遵循标准,以保证软件组件的互操作性,只有遵循统一的标准,不同厂商的、不同时期的、不同程序设计风格的、不同编程语言的、不同操作系统的、不同平台上的软件或软件部件才能进行交流与合作。为此,OMG(ObjectManageGroup)提供了一个对象标准CORBA,它定义了一个网连对象的接口,使得对象可以同时工作。基于CORBA的对象请求代理ORB为客户机/服务器开发提供了中间件的新格式。
      作为OMG成员的微软公司撇开CORBA而另辟了COM(ComponetObjectModel),即组件对象模型,并把COM定位成基于对象的软件开发模型,尽管COM被认为是微软鼓噪出来的技术,但支持COM的开发工具却不断增多,其中大部分来自于微软,包括VisualBasic和VisualC++。
      公共对象请求代理结构:CORBA标准
      全球性网络使线上的所有设备和软件成为全球共享的浩瀚的资源,计算机环境也从集中式发展到分布式环境,开放式系统的发展使用户能够透明地应用由不同厂商制造的不同机型不同平台所组成的异构型计算资源,因此,分布式处理和应用集成自然而然地成为人们的共同要求,那么什么是分布式处理和应用集成呢?它们的功能和关键技术是什么呢?简单地讲,分布式处理和应用集成就是指在异构的、网络的、物理性能差别很大的、不同厂商的、不同语言的信息资源的基础上构建信息共享的分布式系统,并且能够有效地进行应用系统和分布式处理的集成。分布式处理的关键在于定义可管理的软件构件,即面向对象技术中的“对象”。应用集成的关键在于为跨平台、跨机种、跨编程语言的产品提供统一的应用接口。OMG组织针对当今信息产业的要求,公布了CORBA标准,即公共对象请求代理体系结构(CommonObject Request Broker Architecture),这是一个具有互操作性和可移植性的分布式面向对象的应用标准。
      CORBA的核心是对象请求代理ORB,它提供对象定位、对象激活和对象通讯的透明机制。客户发出要求服务的请求,而对象则提供服务,ORB把请求发送给对象、把输出值返回给客户。ORB的服务对客户而言是透明的,客户不知道对象驻留在网络中何处、对象是如何通讯、如何实现以及如何执行的,只要他持有对某对象的对象引用,就可以向该对象发出服务请求。
      CORBA允许用户以两种不同的方式提出对象请求:
      1)静态调用:
      通过给定接口的存根,在编译了对象代码后,进入客户端的程序。因此,静态调用必须在编译时就知道对象及其类型。
      2)动态调用:
      通过ORB的动态调用接口DII,在运行时生成访问对象的代码。
      不管客户以哪一种形式提出请求,ORB的任务是:找出所要对象的位置,激活该对象,向对象传递此请求。对象执行所请求的服务后,把输出值返回给ORB,然后再由ORB返回给客户。
      CORBA的重要概念是:

      1.对象连接

      CORBA广泛地支持对象的实现,在单服务器系统中也可以实现由接口定义语言定义的接口。ORB的灵活性既可以直接集成已有的应用,又不会使新对象受某些原则的制约。
      对象连接提供了有不同类型对象实现时,使用ORB服务的方法,服务包括:对象引用、方法调用、安全控制、对象实现的激活与静候等。

      2.接口定义语言(IDL)

      CORBA用IDL来描述对象接口,IDL是一种说明性语言,它的语法类似于C++。
      IDL提供的数据类型有:基本数据类型、构造类型、模板类型、和复合类型、操作说明。这些类型可以用来定义变元的类型和返回类型,操作说明则可以用来定义对象提供的服务。
      IDL还提供模块构造,其中可以包含接口,而接口是IDL各类型中最重要的,它除了描述CORBA对象以外,还可以用作对象引用类型。
      IDL提供了接口继承性,派生接口可以继承其基类接口所定义的操作与类型。IDL的接口继承性有其特殊性,此处不赘述。
      总之,CORBA的IDL是一种说明性语言,描述面向对象系统开发所遵循的接口与实现相分离的基本原则。

      3.动态调用接口

      把IDL说明编译成面向对象程序设计语言的实代码后,客户可以调用已知对象的操作。在某些应用中,用户并不了解应用接口编译信息,但也要求调用对象的操作,这时就要动态调用接口来调用用户的操作了。例如,图形用户接口应支持用户浏览接口公共库,以获得每个对象所支持的操作信息,用户可根据自己的需求从浏览对象中挑选出所需的对象操作,具体的对象操作的调用实际上是用动态调用接口来完成的。

      4.接口公用库

      接口公用库持久地存储IDL的接口说明,借助于接口公用库,可以实现对象继承性层次结构的导航,并且提供了有关对象支持的所有操作的描述。接口公用库最常见的功能是为接口浏览器提供信息,帮助应用开发者找出潜在的可重用的软件部件。ORB可以利用接口公用库检查运行时的操作参数类型,但接口公用库的基本功能是提供类型信息,为动态调用接口发送请求提供信息支持。
      CORBA的不足之处:
      尽管有多家供应商提供CORBA产品,但是仍找不到能够单独为异种网络中的所有环境提供实现的供应商。不同的CORBA实现之间会出现缺乏互操作性的现象,从而造成一些问题;而且,由于供应商常常会自行定义扩展,而CORBA又缺乏针对多线程环境的规范,对于像C或C++这样的语言,源码兼容性并未完全实现。
      CORBA过于复杂,要熟悉CORBA,并进行相应的设计和编程,需要许多个月来掌握,而要达到专家水平,则需要好几年。

     

    一、什么是Java IDL

    ----Java IDL(InterfaceDefinition Language)可实现网络上不同平台上的对象相互之间的交互,该技术基于通用对象请求代理体系结构CORBA规范说明。IDL是不依赖于语言的接口定义语言,所有支持CORBA的语言都有IDL到该语言的映射。就像其名字所表示的那样,Java IDL支持到Java语言的映射。CORBA规范说明和IDL映射是由OMG(ObjectManagement Group)定义的。OMG由700多个成员组成,Sun公司是其成员之一,它在定义IDL到Java映射的工作中起了主要作用。

    ----JDK1.1给Java开发人员提供了开发100%纯Java分布式应用的功能,即远程方法调用Java RMI。而Java2平台提供的JavaIDL可以在分布式应用中使用非Java语言,也就是说,Java2平台提供的ORB(ObjectRequest Broker)可以和任何遵从CORBA规范的ORB互操作,包括IONAT echnologies的Orbix、Visigenic Software的Visi Broker、IBM的Component Broker等。目前,主要的Web浏览器(MicrosoftIE4.0和NetscapeNavigator4.0)实现的主要是JDK1.1中的功能。不过,利用Sun公司提供的Java插件(Plug-in)可以使浏览器具备Java2平台的所有特征。

    ----需要说明的是,Java2平台提供了两种不同的方法来构造分布式应用系统,即Java RMI和Java IDL,它们具有相似的特征和功能,Java RMI支持用Java语言写的分布式对象,Java IDL可以与支持CORBA的任何程序设计语言如C、C++、COBOL等写的分布式对象交互。这两种方法各自具有不同的特点:

    ----(1)100%纯Java和对遗产应用系统(legacy system)的支持。JavaRMI是对分布式应用系统的100%纯Java解决方法,具有Java的"Writeonce, run anywhere"的优点。用JavaRMI开发的应用系统可以部署在任何支持Java运行环境的平台上。

    ----相反,JavaIDL是基于CORBA规范标准的技术,可以远程调用非Java语言编写的对象,因此Java IDL提供了对那些用非Java语言开发的遗产应用系统的支持。

    ----(2)使用不同的通信协议。Java RMI和Java IDL目前使用不同的通信协议,Java IDL使用CORBA/IIOP协议,IIOP(InternetInter-ORBProtocol)协议可以使位于不同平台上、用不同语言写的对象以标准的方式进行通信;Java RMI目前使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通信,JRMP是专为Java的远程对象制定的协议,不过Sun和IBM已经宣布将来会支持在RMI中使用IIOP协议,以便和遵从CORBA规范的远程对象通信。

    ----(3)通过引用调用对象还是通过值调用对象。在Java IDL中,客户端通过引用与远程对象交互,即客户机使用桩(Stub)对远程服务器上的对象进行操作,但并不拷贝服务器上的对象。

    ----相反,RMI使得客户机可以通过引用和远程对象交互,也可以把远程对象下载到客户机运行环境进行操作,由于在RMI中使用的对象都是Java对象,因此RMI使用Java中的对象串行化(Serialization)功能在服务器和客户机之间传输对象。不过CORBA规范的以后版本将包括按值调用对象的功能。

    ----Java RMI和JavaIDL各有自己的优缺点,从某种意义上说,RMI可以看作是RPC(Remote Procedure Calls)的面向对象版本。RMI的最大优势是可以用它来提供100%纯Java的解决方案,这意味着构造RMI应用系统将比较简单,但这也正是基于RMI的应用系统的一个缺点,即只能在Java环境中运行,不能充分利用遗产应用系统。

    ----Java RMI和JavaIDL均可满足一定范围的用户需求,都适用于一定范围的应用,两者之间存在着重叠,有些应用可使用两者中的任何一种技术开发,但对于某些应用来说,采用其中的某一种比采用另一种更为恰当。

    二、使用CORBA和JavaIDL

    ----从1989年以来,OMG一直致力于开放的软件总线体系结构CORBA的规范说明的定义,利用CORBA,不同供应商开发的、运行在不同平台上的构件可以互操作,而不管该对象位于何处,用什么语言实现。Java IDL使得Java也支持CORBA规范说明。作为Java企业计算API的一部分,Java IDL可以保证企业异质计算中的无缝互操作性和可连接性。

    ----CORBA对象和一般的程序设计语言中的对象的区别在于:

      CORBA对象可以位于网络中的任何位置;

      CORBA对象可以和其他平台上的对象交互;

      CORBA对象可以用任何程序设计语言编写,只要有IDL到该语言的映射即可(目前已包括到Java、C++、C、Smalltalk、COBOL、Ada等语言的映射)。

    ----接口定义语言IDL用于定义CORBA对象的接口,所有的CORBA对象都支持IDL接口。IDL语法和C++非常类似,利用Java IDL,可以在Java中定义、实现、存取CORBA对象。对于每个IDL,idl to java生成一个Java接口和其他一些必要的.java文件,包括一个客户端桩(Stub)和服务器端骨架(Skeleton)。

    ----为了使用JavaIDL,需要有idl to java编译器,idl to java产生和任何遵从CORBA规范的ORB一起工作的客户端桩和服务器端骨架,Java2平台中包括CORBAAPI和ORB,使得Java应用系统通过IIOP协议可以调用远程的CORBA对象,JavaORB支持暂态(Transient)CORBA对象,提供了暂态名字服务器把对象组织成树目录结构,名字服务器遵从CORBA中COS规范说明的命名服务规范说明(Naming Service Specification)。

    ----图1说明了从客户端到服务器发送一个消息请求的过程,其中客户端也可以是一个CORBA对象:

    ----客户机不需要了解CORBA对象的位置与实现细节,也不需要了解哪个ORB用于存取对象。

    ----在客户端,应用系统包括远程对象的引用,对象引用使用桩方法作为远程方法的代理,这个方法事实上在ORB中的,所以调用桩方法会调用ORB的连接功能,ORB会把对桩方法的调用传递到服务器端。

    ----在服务器端,ORB利用骨架代码把远程调用转换成本地对象的方法调用,骨架需要对调用和参数的格式进行转换。同时,当方法返回时,骨架对结果进行变换,然后通过ORB把结果返回给客户机。

    ----不同的ORB之间通过IIOP协议进行通信,IIOP是建立在TCP/IP之上的协议。

    ----CORBA目前还处于发展阶段,一些标准还在定义之中,但CORBA中的大部分基本结构已经定义,许多软件供应商已根据CORBA的定义作了很多开发工作,Java IDL就是该规范说明的一个实现。但在Java2平台中,并没有实现CORBA规范说明中的所有特征,如:

      接口库:在一般的Java IDL操作中并不需要接口库,Java客户机可以存取其他的接口库,如C++ORB提供的接口库;

     RMI/IIOP协议;

      按值调用对象;

      IDL中的一些类型如wchar、wstring、longdouble等。

    三、IDL到Java的映射

    ----为了使Java支持CORBA规范说明,需要一个把IDL中的元素映射为Java中元素的标准途径,Sun已经制订了两者之间的映射规则,并提供了编译器idl to java,以便从IDL得到相应的桩和骨架。

    ----下表列出了一些IDL中元素和Java中元素的映射关系。

    ----和Java中的接口一样,IDL接口不包含方法的具体实现,Java开发人员需在Java类中提供对这些方法的具体实现。

    四、使用Java IDL开发应用的过程及实例

    ----用JavaIDL开发分布式应用系统一般可分为五个步骤:

    ----1.定义远程接口

    ----用IDL定义远程对象的接口,使用IDL而不是Java语言是因为idl to java编译器可以自动地从IDL产生Java语言的桩和骨架源文件,以及和ORB连接时所需要的一些代码。使用IDL,开发人员可以用其他语言来实现客户机和服务器。如果要为一个已经存在的CORBA服务实现客户机,或为一个已经存在的客户机实现服务,则首先要给出IDL接口,然后运行idl to java编译器产生桩和骨架,在此基础上再进行实现。

    ----2.编译远程接口

    ----在IDL文件运行idl to java编译器,产生Java版本的接口,以及桩和骨架代码文件,这些代码文件使得应用程序可以和ORB相连接。

    ----3.实现服务器

    ----把idlto java编译器产生的骨架和服务器应用程序集成在一起,除了要实现远程接口中的方法之外,服务器代码还要包括启动ORB以及等待远程客户机的调用等部分。

    ----4.实现客户机

    ----类似地,以桩作为客户端应用程序的基础,客户机建立在桩之上,通过Java IDL提供的名字服务查询服务器,获得远程对象的引用,然后调用远程对象中的方法。

    ----5.启动应用程序

    ----一旦实现了服务器和客户机,就可以启动名字服务,接着启动服务器,然后运行客户机。

    ----下面以一个经典的HelloWorld程序来说明具体的开发过程。HelloWorld包含一个操作,该操作返回一个字符串并打印出来,Client和Server之间的通信过程如下:

    ----(1)客户端应用程序或小应用程序调用HelloServer的sayHello操作;

    ----(2)ORB把调用传递到已注册的服务对象;

    ----(3)服务对象运行sayHello方法,返回一个Java字符串;

    ----(4)ORB把该字符串返回给客户机;

    ----(5)客户机打印该字符串的值。

    ----尽管HelloWorld程序比较简单,但它涉及到的任务和几乎任何一个使用CORBA静态调用的分布式应用系统所涉及到任务相同,图2说明了如何用CORBA在客户机和服务器之间实现经典的"HelloWorld"程序。

    ----首先是定义Hello.idl,下面是用IDL描述的Hello.idl,只有一个操作(方法),该操作返回一个字符串。

     Module Hello App

      {

     interface Hello

      {

     stringsay Hello ( );

      };

      };

    ----然后把Hello.idl文件映射为Java源代码文件,用以下命令编译Hello.idl文件:

    ----idl to javaHello.idl

    ----根据命令行中的不同选项,idl to java编译器产生不同的文件,上面这条命令将创建子目录HelloApp并在其中产生五个文件:_HelloImplBase.java、_HelloStub.java、Hello.java、HelloHelper.java、HelloHolder.java。

    ----要完成该应用程序,还要分别在这五个文件的基础上提供服务器端和客户机端的实现。

    ----CORBA服务器程序的结构和大部分Java应用程序的结构一样,即导入所需要的包,声明服务器类,定义main方法,处理一些例外等。另外,CORBA服务器要有一个ORB对象,每个服务器实例化一个ORB,并向其注册服务对象,因此当ORB接收到调用请求时可以寻找到服务器。最后是服务对象的管理,服务器是一个进程,实例化了一个或多个服务对象,服务对象具体实现接口中说明的操作。HelloServer和命名服务一起工作,使得服务对象对于客户机来说是可用的,服务器需要对名字服务的对象引用,可以向名字服务注册,并保证向Hello接口的调用被路由到其服务对象上,最后是等待客户机的调用。

    ----CORBA客户机的结构和大部分Java应用程序的结构基本相似,即导入所需要的包、声明应用类、定义main方法、处理一些例外等。另外和服务器程序一样,一个CORBA客户机也需要本地的ORB来执行所有的配置工作,每个客户机实例化一个org.omg.CORBA.ORB对象,然后向该对象传递一些必要的信息以进行初始化,最后是利用ORB取得所需要的服务。一旦一个应用有了ORB,即可通过ORB来确定应用所需要的服务的位置,在本例子中即是Helloserver。为了调用CORBA对象中的操作,客户端应用要有对该对象的引用,有很多种方法可以得到这种引用,如调用ORB.resolve_initial_references或使用其他的CORBA对象(如命名服务),当在分布式环境中没有命名服务可用时,CORBA客户机使用字符串化对象引用(Stringifiedobjectreference)来得到其第一个对象。

     

     

    1.4 接口定义语言(IDL)

    一个IDL文件定义公共的应用程序接口(API),通过服务程序中的对象向外公布。一个CORBA对象的类型称作接口,与C++中的类或者Java中的接口类似。IDL接口支持多重继承。

    一个IDL文件示例如图1.1所示。IDL接口可以包括方法和属性。很多人都误以为一个IDL接口的属性类似于C++中的示

    例变量(或者Jave中的域)的概念。这是错误的。一个属性只是在语法上对一对儿get-和set-类型方法的称谓。属性可以是只读的,这种情况时该属性只有一个get-类型的方法。

    module Finance {

       typedef sequence<string> StringSeq;

       struct AccountDetails {

       string name;

       StringSeq address;

       long account number;

       double current balance;

        };

       exception insufficientFunds { };

       interface Account {

           void deposit(in double amount);

           void withdraw(in double amount)

               raises(insufficientFunds);

           readonly attribute AccountDetails details;

        };

    };

    *****************************************************************************************************

    图1.1: IDL文件示例

    方法的参数有一个指定的方向,可以是in(意味着参数由客户程序传入服务程序),out(参数从服务程序传回客户程序)或者inout(参数是双向传递的)。方法同样可以有返回值。方法在某块出错时可以引发(抛出)一个异常。有30多种预定义的异常类型,称作系统异常,他们都可以由方法抛出,尽管在实际系统中CORBA运行时系统引发的异常多于应用程序代码引发的。除了预定义的系统异常,新的异常类型可以在IDL文件中定义,这些异常可称为用户定义的异常。方法署名的raises子句指定该方法可能抛出的用户定义异常。

    方法的参数(包括返回值)可以是内置类型的一种——例如:string,boolean或者long,也可以是IDL文件中定义的用户自定义的类型。用户定义类型可以是一下的任意一种:

    结构体。类似于C/C++中的结构体或者Java中只包含公共域的类。

    序列。集合类型,就像一个可以增或减的一维数组。

    数组。IDL数组的维度在IDL文件中指定,所以数组是固定大小的,这就是说他不能在运行时增或者减。数组在IDL中很少用到。序列类型更灵活,所以用的更多。

    自定义。给现存的类型定义一个新名字。例如,下面的语句定义age可用来描述short。

       typedef short age;

    默认情况下,IDL的序列和数组是匿名类型,也就是说他们没有名字。通常使用typedef的重要意义在于给序列或者数组的声明关联一个名字。例句可以在图1.1中StringSeq的定义中看到。

    联合体。该类型可以在运行时保留多个值中的一个。例如:

    union Foo switch(short) {

       case 1: boolean boolVal;

       case 2: long longVal;

       case 3: string stringVal;

    };

    一个Foo类型的实例可以保存一个boolean、long或者string值。前面的case标记(成为判别式)表明当前是哪种值。与IDL联合体相同的理念可以在很多面向过程的语言中找到。但是,他们很少在面向对象的语言中使用,因为多态统称能以更好的方式达到同样的目的。

    枚举类型。枚举在概念上类似于一个常整型集合的声明。例如:

    enum color (red, green, blue );

    enum city (Dublin, London, Paris, Rome );

    从本质上说,CORBA使用整数表达不同的枚举值,使用枚举声明的好处在于很多编程语言都有对它的内在支持,或者相似的机制,可以用来进行强类型判识,这样程序员就不会将city变量和color变量相加。

    定点类型。定点类型保存定点数值,而float和double类型保存浮点数值。浮点计算适用于很多用途,但是,可能导致几个小数位后的舍入误差。对比来说,定点数值可能比对应的浮点数值占用更多的内存空间,但是他们有避免舍入误差的优点。使用定点数值趋向于限制在适当的应用领域。例如金融计算和数字信号处理等。尽管一个工程使用定点类型数字,它很可能使用定点计算作为细节实现却不将定点数字的使用公布为公共的IDL接口。由于以上原因,定点类型很少在IDL文件中声明。

    值类型。在9.2节、96页讨论。

    IDL类型可以组织在一个module中。module结构与C++中的namespace或者Java中的package有异曲同工之妙,也就是说,他事先给类型名称前添加了一个前缀,以避免命名空间冲突。IDL中的域操作符是“::”。例如,

    Finance::Account是Finace模块中定义的Account类型的全域名

     

    编译 IDL 后生成的 Java 类

    Helper         

    为接口客户提供有用的助手功能的类。编译器为 narrow 功能自动生成代码,这种 narrow 功能让客户将CORBA对象引用强制转换为接口类型。还提供了绑定(bind)功能,用户可以用其查找该类型的对象。

     

    Holder         

    含有接口类型的公共实例成员的类。用户和服务器用其来以方法调用的 out 和 inout 参数的形式传递接口类型的对象

     

    Stub           

    为接口对象实现客户端存根的类,它是真正的提供排列功能的接口的内部实现。

     

    Operations

    定义了 IDL 功能的类。

     

    Tie            

    CORBA支持两种类型的程序:基于继承(inheritance-based)的和基于委托的(delegantion-based)。Tie类只是扩展了POA,但它没有提供自己的实现语义。它把所有的工作委托到一个实现对象上。每一个Tie对象存储一个实现对象的引用。

    委托方法可用两种类实现IDL接口:1.一个IDL生成的Tie类,该类继承自POA,但是委托所有的调用到一个实现类;2.一个实现IDL生成的Operations接口的类,它定义了IDL的功能。

     

    POA            

    为接口实现CORBA服务器端框架的类。这个类将 CORBA 和 Java 对象模型组合到一起。它是通过使用一个实现了Java的org.omg.CORBA.Object接口的 Java 对象做到这一点的。这是CORBA根接口,所有得CORBA对象都必须实现它。

     

     

    CORBA IDL-to-Java 映射

    通用结构:

    1.CORBA模块

     ORBA IDL 模块(module)映射成与IDL模块同名的Java包

    2.CORBA异常

     CORBA定义了两类异常

     I.system exceptions               一种被CORBA定义的异常

     II.user-defined exceptions      由用户在IDl中定义的异常         

    3.CORBA 参数

     CORBA定义了三种参数传递模式:in、out和 inout。Java 只支持in 。         

    4.CORBAHolder 类

     由于Java中没有IDLout 和 inout 的对应物,对IDL out 和inout 参数,IDL-to-Java 映射必须提供一些附加的机制来支持值传递(并返回结果)。

     映射定义 Holder 类,这些 Holder 类在Java中实现附加的参数传递模式。对每个IDL out 或 inout 参数,客户必须实例化一个适当的 Holder 类的实例(它是通过值传递的)。

    5.CORBAHelper 类

     Helper 类包含用于不同方式操作IDL的方法。

     Helper 类提供客户可以用来操作类型的静态方法,这些包括该类型的任何插入和取出操作、获得库(repository)ID、获得类型码(typecode)、从流中读取类型并把类型写入流中。

     另外,映射IDL接口的Helper类提供一个静态的narrow方法,可以用于进行强制类型转换。

    6.CORBA属性

     CORBA IDL 接口可以拥有属性,这些都是类型域中set和get操作所需的。

     每个属性都被映射到一对与属性同名的重载Java访问器和修改器方法上。

    结构类型:

    1.sequence(序列)

    一个可变大小的一维元素序列,其中元素可以是任何IDL定义的类型。可以限制序列的最大长度。

    2.struct(结构)

    可以使用结构将多种类型的命名字段组装在一起

    每个struct都有两个构造函数。一个是默认的构造函数,把结构中的所有字段设置为空。第二个构造函数把结构字段作为参数并初始化每个字段

    3.union(联合)

     用于在任何给定的时间只引用几个数据成员中的一个(任何时间,内存中只能有一个成员)。联合使用discriminator标签值来显示该值含有联合中的那个成员。

    4. Any

     Any是一个保留其类型的自描述数据结构,它使你可以在运行时用类型安全的转换函数提取和插入预定义的IDL类型的值。

     Any类型让你指定一个属性值、参数或返回类型,该类型包含一个在运行时而不是在编译时确定的任意类型。可以使用Any传递任何东西。

     

     

     

    IDL-to-Java 的映射

    http://www.ibm.com/developerworks/cn/java/co-corbajct4/index.html

     

    http://www.ibm.com/developerworks/cn/java/co-cjct5/index.html

     

    Java IDL

    http://www.iplab.is.tsukuba.ac.jp/~liuxj/jdk1.2/zh/docs/guide/idl/index.html

     




    展开全文
  • 简介 Go 语言中的接口是种.../* 定义接口 */ type interface_name interface { method_name1([parameter list]) (return_type) method_name2 ([parameter list]) (return_type) ... method_namen([parameter...

    目录

    简介

    结构体

    声明/定义

    实现与使用

    实现

    多接口实现

    接口继承

    空接口

    结构体切片排序

    接口和继承比较

    注意项

    全部代码

    截图

    参考


    简介

    Go 语言中的接口是一种内置的类型,它定义了一组方法的签名,体现了程序设计的高内聚低耦合的特点,本篇文章会介绍接口及基本使用,下篇文章介绍类型断言。

    结构体

    定义Monkey结构体,具有climb方法。

    type Monkey struct {
    	Name string
    }
    
    func (m *Monkey)climb(){
    	fmt.Println(m.Name,"会爬树...")
    }

     定义WuKong结构体,包含Monkey和Tool属性。

    type WuKong struct {
    	Monkey
    	Tool string
    }

    声明/定义

    定义接口模板如下:

    /* 定义接口 */
    type interface_name interface {
       method_name1([parameter list]) (return_type)
       method_name2 ([parameter list]) (return_type)
       ...
       method_namen([parameter list]) (return_type)
    }

    代码

    定义Flyable接口

    type Flyable interface {
    	Fly()
    }

    实现与使用

    实现

    实现了接口的所有方法,就是实现了该接口,不需要显示指明是哪个接口,即隐式实现

    func (w *WuKong) Fly() {
    	fmt.Println("筋斗云,来...")
    }

    鸭子类型

    鸭子类型duck typing)是动态类型的一种风格,例如,Python语言中比较常见。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性集合"决定。

    而在Go中,就是由当前结构体的方法集合决定当前结构体是否实现了某个接口。WuKong可以飞,而Monkey不可以飞,WuKong在继承Monkey的基础上,扩展了自己的功能。

    多接口实现

    再定义一个接口

    type Swimmable interface {
    	Swim()
    }

    实现

    func (w *WuKong) Swim()  {
    	fmt.Println("老龙王,俺老孙的金箍棒呢?")
    }

    WuKong结构体就实现了上面的两个接口。

    接口继承

    再定义一个接口Skills,继承前面的两个接口,并添加新的方法Change

    type Skills interface {
    	Flyable
    	Swimmable
    	Change()
    }

    实现

    func (w *WuKong) Change()  {
    	fmt.Println("看我72变...")
    }

    至此, WuKong结构体实现了四个接口,为什么是四个呢?因为还有下面这一个

    空接口

    type Null interface {
    
    }

    如你所见,什么方法也没有,即每个结构体都实现了空接口,都可以赋值给空接口,这在排序,后面类型断言等部分都很有用。

    结构体切片排序

    func Sort(data Interface)

    Sort,本地排序data,无返回。它调用1次data.Len确定长度,调用O(n*log(n))次data.Less和data.Swap,底层使用的是快排,感兴趣的朋友可以看看快排源代码。本函数不能保证排序的稳定性(即不保证相等元素的相对次序不变)。

    // Sort sorts data.
    // It makes one call to data.Len to determine n and O(n*log(n)) calls to
    // data.Less and data.Swap. The sort is not guaranteed to be stable.
    func Sort(data Interface) {
    	n := data.Len()
    	quickSort(data, 0, n, maxDepth(n))
    }

    Interface接口

    type Interface interface {
    	// Len is the number of elements in the collection.
    	Len() int
    
            // Less reports whether the element with index i must sort before the element with index j.
    	// See Float64Slice.Less for a correct implementation for floating-point values.
    	Less(i, j int) bool
    
    	// Swap swaps the elements with indexes i and j.
    	Swap(i, j int)
    }

     既然这是一个接口,只要我们实现了Len、Less、Swap方法即可传参,进行排序。

    我们就用Monkey结构体的切片实现一下这个接口。

    type MonkeySlice []Monkey
    //--------实现Len--------
    func (m MonkeySlice) Len() int{
    	return len(m)
    }
    //---------实现Less---------
    func (m MonkeySlice) Less(i,j int) bool {
    	return m[i].Name < m[j].Name
    }
    //----------实现Swap---------
    func (m MonkeySlice) Swap(i,j int){
    	m[i],m[j] = m[j],m[i]
    }

    使用

    	monkeys := MonkeySlice{{"峨眉猴"},{"齐天大圣"},{"金丝猴"},{"六耳猕猴"},{"孙悟空"}}
    	sort.Sort(monkeys)
    	fmt.Println(monkeys)

    接口和继承比较

    • A结构体继承了B结构体,那么A结构体就自动的继承了B结构体的字段和方法,并且可以直接使用
    • 当A结构体需要扩展功能,同时不希望去破坏继承关系,则可以去实现某个接口即可,
    • 接口是对继承的补充,是like和is的区别
    • 继承解决代码的复用性和可维护性
    • 接口更加灵活,一定程度上实现了解耦

    注意项

    • 接口不能创建实例,接口可以指向实现了接口的结构体实例
    • 结构体必须实现所有接口的方法才可以说实现了该接口
    • 接口默认是指针类型,没有初始化会输出nil
    • 空接口可以接收任何类型

    全部代码

    package main
    
    import (
    	"fmt"
    	"sort"
    )
    
    type Monkey struct {
    	Name string
    }
    
    func (m *Monkey)climb(){
    	fmt.Println(m.Name,"会爬树...")
    }
    
    //--------Flyable接口---------
    type Flyable interface {
    	Fly()
    }
    
    //--------Swimmable接口-------
    type Swimmable interface {
    	Swim()
    }
    //----------接口继承--------------
    type Skills interface {
    	Flyable
    	Swimmable
    	Change()
    }
    //-----------空接口-----------
    type Null interface {
    
    }
    //---------不破坏结构体,添加属性--------
    type WuKong struct {
    	Monkey
    	Tool string
    }
    //---------不破坏继承,扩展行为/方法--------
    func (w *WuKong) Fly() {
    	fmt.Println("筋斗云,来...")
    }
    
    func (w *WuKong) Swim()  {
    	fmt.Println("老龙王,俺老孙的金箍棒呢?")
    }
    
    func (w *WuKong) Change()  {
    	fmt.Println("看我72变...")
    }
    type MonkeySlice []Monkey
    //--------实现Len--------
    func (m MonkeySlice) Len() int{
    	return len(m)
    }
    //---------实现Less---------
    func (m MonkeySlice) Less(i,j int) bool {
    	return m[i].Name < m[j].Name
    }
    //----------实现Swap---------
    func (m MonkeySlice) Swap(i,j int){
    	m[i],m[j] = m[j],m[i]
    }
    
    func main() {
    	//-----------接口体-------
    	w := WuKong{}
    	w.Name = "孙悟空"
    	//-----------使用方法------
    	w.climb()
    	//-----------使用实现的接口的方法---------
    	w.Fly()
    	//-----------结构体赋值给接口------------
    	var s Skills
    	s = &w
    	s.Change()
    	//----------空接口-------------
    	var null Null
    	null = w
    	wukong := null.(WuKong)
    	wukong.Swim()
    	//-----------结构体切片排序--------------
    	monkeys := MonkeySlice{{"峨眉猴"},{"齐天大圣"},{"金丝猴"},{"六耳猕猴"},{"孙悟空"}}
    	sort.Sort(monkeys)
    	fmt.Println(monkeys)
    }
    

    截图

    参考

    Go标准库-sort

    更多Go相关内容:Go-Golang学习总结笔记

    有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。

    展开全文
  • 环境:python2.7 docker:一、一个简单的python程序既然是一个简单的python程序,那我们就实现一个简单的加法功能即可。#coding=utf-8 import random def add(aStr,bStr):  map={}  try:  a=float(aStr)  b=...
  • 接口定义和作用

    千次阅读 2016-06-17 00:28:15
    接口它只是定义,而不去具体实现,比如一个水桶,你想用它去装水,那么你就在下面的方法中具体写出怎么装水,这个接口只是负责让你装,如果你要装油,那你就具体定义怎么装油,这是的接口也不管你怎么实现,接口只是...
  • 它可以把IDE口转换成USB接口,这样就可以用电脑上的USB口插普通硬盘用了。“易驱线”是需要独立电源的,可是几乎所有“易驱线”的原配电源几乎都有问题:很不稳定。电压不足导致硬盘中途停工是常事儿,伤害硬盘不...
  • C#接口(interface)用来定义一程序的协定。实现接口的类或者结构要与接口定义严格一致。有了这协定,就可以抛开编程语言的限制(理论上)。C#接口可以从多接口继承,而类或结构可以实现多个接口。C#接口...
  • 接口定义和SOA规范

    千次阅读 2008-09-16 16:47:00
    接口定义和SOA规范不在这里重复SOA的定义。SOA从设计思想的角度强调将系统划分为高可复用... 一个自然的想法就是定义一个统一的接口规范,新开发服务的接口遵循这个接口标准,或者服务开发运行平台提供新接口到已有各种
  • 、问题描述 最近公司有需求是,从小程序哪里获取二维码,然后从二维码中解析出URL来,自己定制下二维码。。。嫌微信生成的码太难看了。。。微信小程序的获取二维码的文档如下:...
  • 开发了一个微信小程序项目

    万次阅读 多人点赞 2016-09-28 17:10:15
    于是乎,趁着今天上午空气质量不错,撸了一个程序,放在了男性交友网站上了, 我添加了很全的注释,大家赏个star。地址:https://github.com/yll2wcf/wechat-weapp-lifeTools功能介绍功能比较简单,调用了百度ApiS
  • Android HIDL HAL 接口定义语言详解

    千次阅读 2019-03-11 17:09:41
    在 Andoird 8.0 版本框架代码中,加入了 HIDL(HAL 接口定义语言),HIDL 的出现是为了将用户层和 HAL 层分割开,它指定了 HAL 和用户之间的接口,让用户能够替换 Android 框架,而无需重新编译 HAL,以便让厂商能够...
  • 微信小程序 获取小程序码和二维码java接口开发

    万次阅读 多人点赞 2017-08-30 11:35:07
    微信小程序API文档:获取二维码、简介通过后台接口可以获取小程序任意页面的二维码,扫描该二维码可以直接进入小程序对应的页面。目前微信支持两种二维码,小程序码(左),小程序二维码(右),
  • 一个例子说为什么要用接口

    千次阅读 多人点赞 2018-08-15 20:09:37
    如题,看看下面这个例子 : 现有狗 和企鹅两个类 ,狗会玩飞碟,企鹅会游泳,为什么要把玩飞碟和游泳的方法...假设这样一种情况:后面又多了一种宠物类型鸭子,鸭子也会游泳,你是不是又要在鸭子类中定义一个游泳的...
  • 以下为仅为主板各接口的针脚定义,外接出来的设备接口则应与主板对应接口针脚定义相反,如鼠标的主板接口定义为6——数据,4——VCC,3——GND,1——时钟,鼠标线的接口定义则与之相反为5——数据,3——VCC,4——...
  • [Java] 为什么要定义接口

    千次阅读 2017-11-20 11:21:27
    一个很搞笑的例子: 看看下面程序一个学校里边,有两种人:学生、老师。他们都要吃饭和睡觉。 ------------------------------ public interface 人{ void 吃饭(); void 睡觉...
  • 什么是接口测试?怎样做接口测试?

    万次阅读 多人点赞 2018-08-20 11:17:31
    扫盲内容: 1.什么是接口? 2.接口都有哪些类型?...接口测试主要用于外部系统与系统之间以及内部各个子系统之间的交互点,定义特定的交互点,然后通过这些交互点来,通过一些特殊的规则也就是协议...
  • Android应用模块之间的交互方式和接口定义主要包括下面方面: 1.Android框架提供的API,这里的API需要参考Android的发行版本来选择,比如:Android 4.0对应的是API 14。 Q:如何找到参考? A:所有的API定义...
  • 细心的读者会发现,这几篇文章分析的Binder接口都是基于C/C++语言来实现的,但是我们在编写应用程序都是基于Java语言的,那么,我们如何使用Java语言来使用系统的Binder机制来进行进程间通信呢?这就是本文要介绍的...
  • RS232 422 485定义接口、接线图

    万次阅读 2013-05-16 21:34:51
    RS232接口 RS232接口是1970年由美国电子工业协会(EIA)联合贝尔... 该标准规定采用一个25个脚的DB25连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。随着设备的不断改进,出现了代替D
  • C#接口定义、特点、实现和应用

    千次阅读 2016-04-13 00:21:31
    C#接口的使用能够使我们的程序有什么改进?那么我们首先我们来看看C#接口特点以及具体的实例使用分析: C#接口特点1:都是“虚的”不能被实例化,这也是接口中为什么不能包含字段--成员变量的原因 C#接口特点2...
  • Linux驱动程序开发 - 设备控制接口

    千次阅读 2009-12-29 09:08:00
    序言设备驱动程序一个基本功能就是管理和控制设备,同时为用户应用程序提供管理和控制设备的接口。我们前面的“Hello World”驱动程序已经可以提供读写功能了,在这里我们将扩展我们的驱动以支持设备控制接口,在...
  • OpenGL简介OpenGL是一种应用程序...在OpenGL 3.0以前的版本或者使用兼容模式的OpenGL环境,OpenGL包含一个固定管线(fixed-function pipeline),它可以在不使用着色器的环境下处理几何与像素数据。我们看到的glBegin
  • PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件) http://www.cnblogs.com/jacklu/p/4687325.html 本篇文章将对PCIe驱动程序的源文件代码作详细解释与说明。整个WDF驱动程序工程共包含4个头...
  • 定义一个rectangle类、让它具有下面的功能:   int main() { int area(rectangle&amp; a);  rectangle s(4,6);  s.width( ); //width=4  s.length( ); //length=6  s.print( ); //width=4,length=6...
  • 支付宝接口程序、文档及解读

    千次阅读 2015-03-11 09:32:57
    很早之前的篇文章 ,记录下来 ,以备不时之需 最近需要为网站加入支付宝的充值接口,而目前关于支付宝接口开发的资料比较杂乱,这里就我此次开发所用到的资料进行汇总整理,希望能够帮助需要的朋友。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 460,169
精华内容 184,067
关键字:

下面是定义一个接口a的程序