================================================================================
Qomolangma OpenProject v1.0

类别    :Rich Web Client
关键词  :JS OOP,JS Framwork, Rich Web Client,RIA,Web Component,
          DOM,DTHML,CSS,JavaScript,JScript

项目发起:aimingoo (aim@263.net)
项目团队:../../Qomo_team.txt
有贡献者:JingYu(zjy@cnpack.org)
================================================================================

一、Qomolangma中的接口(Interface.js)
~~~~~~~~~~~~~~~~~~

在做AOP(面向切面编程)系统之前,我一直在想:有什么必要在JavaScript中做“接口(Interface)”的
机制。——当然,这也说明,你可能需要通过阅读迟些提供的、关于AOP框架的文档,才能理解如何使用
Qomo中强大的接口机制。^.^

接口是现代软件工程中的一种常用工具,它的出现使设计人员更多的关注于功能的“对外表现”,而非
“内部实现”。在软件模型设计中,类图通常用于描述设计的细部,而接口则更常用于描述模块、层次
间的交互关系。

然而这仍然停留在“设计”层面。在C++中,你会看到“接口是抽象类”这样的描述。换个说法,C++认
为接口只是“没有实现的类”。如果这样来描述的话,JavaScript中就没有必要实现一个“接口机制”。

所以,我们看到altas中,接口的实现就简单得多。例如:
---------------
// 1. 声明接口
Web.IArray = function() {
  this.get_length = Function.abstractMethod;
  this.getItem = Function.abstractMethod;
}

// 2. 注册接口,以及为类注册接口
Type.registerInterface("Web.IArray");
Type.registerClass('Web.UI.Data.DataControl', Web.UI.Control, Web.IArray);

// 3. 接口操作(方法)
Function.prototype.implementsInterface = function(interfaceType) { ... }
Function.prototype.isImplementedBy = function(instance) { ... }
---------------

同样的原因,altas中的接口也仅在极少数的地方得以应用。例如在属性检测(类似反射)时,有这样的
代码:
---------------
Web.TypeDescriptor.getProperty = function(instance, propertyName, key) {
    if (Web.ICustomTypeDescriptor.isImplementedBy(instance)) {
        return instance.getProperty(propertyName, key);
    }
    // ...
}
---------------

我们看到atlas中的接口主要用于“检测一个类(或对象实例)”是否实现过某接口。这用于保障后续代
码能安全的执行。本质上,altas是用registerInterface()的机制,来使开发人员不必使用'in'运算来
检测属性。因而上面的代码事实上写成这样也没有关系:
---------------
Web.TypeDescriptor.getProperty = function(instance, propertyName, key) {
    if ('getProperty' in instance) {
        return instance.getProperty(propertyName, key);
    }
    // ...
}
---------------

——然而,这仅仅只是“接口机制”应用的一个方面而已。

在Qomo中,接口不单单是描述,也是实现。实现的接口(的方法)可以被调用,这与Win32中的COM机制
是类同的。Qomo在实现了更加完整的接口特性,并在这样的基础之上,完整地实现了AOP的种种特性。

与JSEnhance.js一样,Qomo中的Interface.js可以脱离Qomo项目运行。

二、概念:接口是描述,也是实现
~~~~~~~~~~~~~~~~~~

接口最基础的定义就是“描述对象的行为”。所以根本上来讲,下面的声明:
---------------
Web.IArray = function() {
  this.get_length = Function.abstractMethod;
  this.getItem = Function.abstractMethod;
}
Type.registerClass('Web.UI.Data.DataControl', Web.IArray);
---------------
将表明下列的含义:
  - 类Web.UI.Data.DataControl实现了Web.IArray接口
  - 类Web.UI.Data.DataControl的实例(instance)将必然具有如下方法:get_length()和getItem()

接口描述了对象实例的行为能力,只是接口机制的一个方面。在COM框架、以及一些其它高级语言的接
口语义中,接口也表明了一种实现。这种“实现”体现在三个方面:
  - 用户可以通过接口,来持有一组对象方法的引用
  - 用户可以通过聚合、包含和委托等技术,来使对象包含多个接口
  - 用户代码可以通过一个接口,来查询“实现接口的对象”的更多接口(以及行为能力)

例如(delphi source):
---------------
type
  IMyObject = interface
    // [a guid for COM framework]
    function run(): boolean;
  end;

TMyObject = Class(TObject, IMyObject)
    //...
  end;

var
  obj : TMyObject;
  intf : IMyObject;

// ...
obj := TMyObject.Create;
if obj.GetInterface(IMyObject, intf) then
  intf.run();
---------------

在这个例子中,接口IMyObject可以用于变量的类型声明。而将intf声明为IMyObject类型,也表明
intf接口指针“从对象实例中取得有效的接口实现”。GetInterface()是COM中的QueryInterface()
的另一个实现,用于从obj中取接口引用。

一旦intf变量成功的获取一个“已实现的接口(一组对象方法指针的引用)”,那么接下来就可以调
用这些接口方法了,例如执行:intf.run()。

三、Qomo中的接口之一:接口的基本语法及实现
~~~~~~~~~~~~~~~~~~

1. 接口声明
  ----------
  Qomo中的接口声明比较简单,采用与altas(以及其它OOP框架)兼容的代码:
---------------
IMyObject = function() {
  this.method = Abstract;
}

IMyObject2 = function() {
  this.method = Abstract;
  this.method2 = Abstract;
}
---------------

Abstract是一个在Qomo中全局提供的、类似关键字的函数。这在讲述OOP框架时已经提及过。不过它
现在被从Object.js中移到了Interface.js中。Abstract()调用的结果是触发一个异常,这也意味着
使用new()创建出的任何一个接口实例,其方法调用都将失败。

Qomo中允许使用类似继承的方式来声明接口。但Qomo不推荐接口继承,因此如果你希望接口“继承
自”其它接口,那么建议用下面的代码来声明:
---------------
IMyObjectEx = function() {
  IMyObject.call(this);

this.method_ex = Abstract;
}
---------------
使用显式的IMyObject.call()的原因,是使得开发人员在阅读代码时能清晰地了解这里有一个继
承关系。——换而言之,父级接口的修改将影响到子级接口的声明。

当然,这种方式也给一些接口声明带来了方便,例如在Interface.js中声明的:
---------------
IAspectedClass = function() {
  IClass.call(this);
  IJoPoints.call(this);
}
---------------

最后补充一点:不要在接口声明中对构造器加入口参数。因为接口不需要、也不应当通过可变参
数来“创建”。

2. 接口注册
  ----------
  Qomo中接口注册有两种形式:
    - Interface.RegisterInterface(obj, intf1 [, intf2 ... intfn]);
    - Class(<BaseClass>, <ConstructorName> [, intf1 .. intfn]);

第一种形式可以为任何的JavaScript对象,包括原生的对象、函数等注册接口。这种形式存在一
个完全等义的全局函数RegisterInterface()。——事实上这指向同一个函数——在Qomo的内部代
码中,只使用Interface.RegisterInterface()这种完整形式。

第二种形式在Object.js中实现。Interface.js中用了少量的代码来使得“类的所有实例、和子类
拥有相同的接口”。如果你使用Qomo的OOP系统,那么只需要在调用Class()进行类注册的时候加
上一个实现的接口表即可。

可以通过Aggregate()来注册“聚合的”接口,这一部分放在后面单独讲述。

作为特例:对undefined和null对象注册接口返回一个-1值。

3. 接口查询
  ----------
  Qomo中可用下面的形式来获取对象(含Qomo和原生的JavaScript对象)的注册接口:
    - Interface.QueryInterface(obj, aInterface);

与注册过程相同,接口查询也有一个完全等义的全局函数QueryInterface(),并且Qomo内部只使
用完整形式的调用。

QueryInterface()将返回一个接口的实现,也就是一个可以调用的接口(对象/指针)。例:
---------------
function MyObject() { }
TMyObject = Class(TObject, 'MyObject');

var obj = new MyObject();
var intf = QueryInterface(obj, IObject);

document.writeln(intf.hasAttribute('Name'));
// output: false
---------------

如果查询null或undefined的接口,或者传入了无效的、未注册的接口同,QueryInterface()将
抛出异常。如果返回undefined,则表明不包含该接口。——此时在用户代码中,该接口引用应
该不被继续处理,而不是盲处理。

QueryInterface()能够查询通过Aggregate()来注册“聚合的”接口。

4. 其它
  ----------
  接口系统提供一个函数来检测一个“声明”是否是接口。如果要在QueryInterface()之前检测一
个接口是否被注册过,可以使用如下函数(返回true/false):
  - Interface.IsInterface(intf);

如果一段声明代码没有(隐式地)被注册到Qomo系统中,那么使用该声明来QueryInterface()会导致
一个异常。——将“接口声明”注册到Qomo的行为隐式地包含在RegisterInterface()和Class()等
调用的过程中。

如果你真的需要在一个接口被实现之前就注册它,那么你可以将它注册给IInterface。尽管这看起
来不怎么合理,但在Qomo中,这是唯一能被理解的方式:
---------------
IMyCustomIntf = function() { ... };
Interface.RegisterInterface(IInterface, IMyCustomIntf);
---------------

在Qomo内核中是具有“将声明直接注册(封装)成接口”的能力的,这就是Interface.js中实现过的
warpInterface()函数。但它不提供给用户代码使用。系统中通过这种方法注册的接口包括:
  - IInterface
  - IJoPoint
  - IMuEvent
  - IJoPoints
如果需要,你可以将自己需要(预先)注册的接口加入到Interface.js的代码中。当然,这并不是一
种推荐的形式。

Qomo提供一些对接口的演示和示例。在Qomo代码包中:
  /Framework/DOCUMENTs/T_InterfaceQuery.html     : 演示接口机制的基本原理
  /Framework/DOCUMENTs/T_InterfaceAggregate.html : 演示脱离Qomo使用接口、聚合的基本使用
  /Framework/DOCUMENTs/BaseObjectDemo4.html      : Qomo中的接口系统的使用示例和基本特性

四、Qomo中的接口之二:(内部)聚合接口的语法
~~~~~~~~~~~~~~~~~~

在COM中,分离接口的方法包括“聚合”和“包含”;在Delphi中,在编译器级别提出了“委托”来
实现接口分离的技术。三者之间只是实现技术和时间上的差异,其效果是基本一致的。

基本上来说,接口隔离原则(Interface Segregation Principle)基于“使用多个专门的接口比使用
单一的总接口总要好”。因此,这事实上是使一个对象同时具有多个接口的技术。在Qomo中,下面两
种语法都可以实现这个目标:
    - Interface.RegisterInterface(obj, intf1 [, intf2 ... intfn]);
    - Class(<BaseClass>, <ConstructorName> [, intf1 .. intfn]);

然而,这两种接口注册的方式要求对象/类显示的具有接口指定的方法。也就是说:如果对象obj注册
了接口intf,则 intf.XXXXX 方法将直接指向obj.XXXXX方法。

然而,我们举个例子来说: TMyObject作为类,总是有对象构造过程的,这表明TMyObject应该具备这
样接口:
---------------
IObjectConstructor = function() {
  this.OnNewInstance = Abstract;
}
---------------

但我们也知道,我们不能把一个OnNewInstnace事件放在TMyObject类上,或者放在obj实例上。——因
为它并不是实例的使用者所关注的。而且,更重要的是,“对象构造过程”在Qomo中被隐含在Class()
的实现代码内部,我们需要一种机制将它的这个能力public出来,这样才能做到“接口是实现”。

在Delphi中,接口的声明方法可以“在对象的私有域中实现”。这时可以通过接口“在对象/单元外”
访问该方法。这体现了“接口表现对象的能力,而不关注具体实现(是私有、公有或者委托)”这一接口
的基本原则。

在Qomo中,综合上述的这些问题及其解决方案,实现了“(内部的)聚合接口”这一特殊的机制。

1. 声明聚合(在函数内部)
  ----------
  Qomo的聚合首先是“为了表现目标的内部具备的行为能力”而提供的。而JavaScript中,提供行为能
力的,只有对象(构造器)和函数。因此,“声明聚合”的行为通常应当发生在一个函数的内部。例如:
---------------
function MyFunc() {
  // Aggregate()与RegisterInterface()有相同的入口参数
  var intfs = Aggregate(MyFunc, intf1 [, intf2 .. intfn]);
}
---------------

由于这会导致每次执行MyFunc都会调用Aggregate(),因此Qomo推荐如下的语法来声明一个带有聚合接口
的函数:
---------------
MyFunc = function () {
  function _MyFunc() {
    // (函数自身的实现代码...)
  }

var intfs = Aggregate(_MyFunc, intf1 [, intf2 .. intfn]);
  // (实现接口 ...)

return _MyFunc;
}();
---------------

由于这样做仅是为了避免重复地调用Aggregate(),因此事实上用户也可以这样来声明(尽管同样麻烦):
---------------
function MyFunc () {
  if (a_aggregated_tag == false) {
    var intfs = Aggregate(_MyFunc, intf1 [, intf2 .. intfn]);
    // (实现接口 ...)
    a_aggregated_tag = true;
  }

// (函数自身的实现代码...)
}
---------------

2. 实现接口
  ----------
  Aggregate()只是建立对象与接口之间的关系并返回一个“Interfaces对象”,这个接口集合中所有的
接口都是未被实现过的。这仍然需要由用户代码来完成,例如:
---------------
IMyFunc = function() {
  this.getLength = Abstract;
}

MyFunc = function () {
  var arr = new Array(5);

function _MyFunc() {
    // (函数自身的实现代码...)
  }

// 0). 声明聚合
  var intfs = Aggregate(_MyFunc, IMyFunc);
  // 1). 取指定接口的一个引用
  var intf = intfs.GetInterface(IMyFunc);
  // 2). 实现接口方法
  intf.getLength = function() {
    return arr.length;
  }

return _MyFunc;
}();
---------------

上面的代码中,“Interfaces对象”intfs的GetInterface()方法用于得到一个接口的引用,而接下来的
代码则描述该接口如何被实现。——在这里,可以使用“聚合”、“包含”或者“委托”这些技术之一。
(目前,)Qomo没有直接提供这三种技术的实现方案,只是“老老实实地”逐一实现了该接口的各个方法。

3. 使用接口
  ----------
  前面已经提到过,Aggregate()内部聚合的接口的使用,与普通注册的接口是一样的。如上例:
---------------
var intf = Interface.QueryInterface(MyFunc, IMyFunc);
document.writeln('the length is: ', intf.getLength());
---------------

五、Qomo中的接口之三:接口的实现
~~~~~~~~~~~~~~~~~~

接口的使用示例请参见/Framework/DOCUMENTs/BaseObjectDemo4.html。内部聚合技术的使用示例可
参见/Framework/DOCUMENTs/T_InterfaceAggregate.html。下面讲述Qomo中实现这些技术的一些细节。

1. 基本接口功能的实现
  ----------
Qomo中的接口采用这样的结构来实现Interface关键字及相关的语法:
---------------
Interface = function() {
  //...

function _Interface(obj) { /* Intf1 .. Intfn */
    //...
  }
  _Interface.QueryInterface = function(obj, intf) { ... }
  _Interface.RegisterInterface =_Interface;
  _Interface.IsInterface = isInterface;

return _Interface;
}();
---------------

其中_Interface()用于实现RegisterInterface()与Interface(),它们是等义的。_Interface()首先
调用warpInterface()将除第一个参数之外的其它参数转变成接口,这其实是在该接口声明(函数)上附
加一个'_INTFHANDLE_'属性。——这是目前为止Qomo中唯一尝试改变对象对外的属性的地方。

由于接口本身只是“声明”而不能直接引用,因此加上该属性并不会导致什么麻烦。在warpInterface()
对该属性做了检测,以避免用户通过修改这个值来伪造、套取接口。——尽管这对用户来说也没有什么
意义。^.^

warpInterface()是真正实现RegisterInterface()的关键代码。_Interface()中的另一部分代码用于处
理与"聚合接口(Aggregate)"相关的一些逻辑。——这在后面进一步叙述。

接口中另一个重要的函数是_Interface.QueryInterface。它的实现相对要复杂些,因为它要处理:
  - 对象的接口可以在类注册中通过Class()注册到指定的类,而不必为每一个对象实例注册;
  - Qomo对象或者其它JavaScript原生对象都可以具有自己的接口注册;
  - 函数可以注册内部的聚合接口。
QueryInterface()必要有能力从所有这些可能注册过接口的“对象”中查询到接口。而且还要返回该
接口的一个“有效的、能调用接口方法的”实现。

“实现接口”的基本原理可以参见/Framework/DOCUMENTs/T_InterfaceQuery.html。其基本步骤是:
  - 创建指定接口的实例:intf = new IYour_Intf();
  - 为接口的每一个“虚方法”重新封装一个调用方法,该方法将实现该接口的对象的同名方法;
  - 特殊处理:任何对象都可以有IInterface接口,将持有QueryInterface()的一个引用。

2. 聚合接口功能的实现
  ----------
在对_Interface()的实现过程中特殊处理了Aggregate():
---------------
    // register aggregated interfacds. is special!
    if ((typeof obj == 'function') || (obj instanceof Function)) {
      if (_Interface.caller===Aggregate && this!==Aggregate) {
        // ...
      }
    }
---------------
也就是说如果:
  - "obj"是一个函数对象,且
  - 通过调用Aggregate()函数来注册它的接口,且
  - this对象不是Aggregate()自身
则_Interface()将尝试把目标对象"obj"与一个"Interfaces"对象(this)分别添加到两个数组:
---------------
   $Aggrs.push(obj);   // 拥有接口的对象(总是一个函数)
   $Aggri.push(this);  // 所拥有的接口集合对象
---------------

而在Aggregate()工具函数中,将两次调用Interface.RegisterInterface(),也就是前面提到的
_Interface()函数。这两次调用的作用并不一样:

第一次采用标准格式调用RegisterInterface(),这时传入的this将是_Aggregate()函数的引用:
---------------
      Interface.RegisterInterface.apply(_Aggregate, arguments);
---------------
代码中,由于Aggregate()与RegisterInterface()的入口参数声明是一样的,因此apply()的第
二个参数直接使用了arguments。这样就首先将接口注册到了指定的对象上。

第二次采用特殊格式调用RegisterInterface(),这时传入的this将是“接口集合”Interfaces
的一个实例,而唯一的一个入口参数foo,将指向被注册接口的函数对象引用:
---------------
      return Interface.RegisterInterface.call(new Interfaces(arguments), foo);
---------------
这次调用,RegisterInterface()将返回传入的this,也就是“接口集合”对象。这样做只是为了
省掉在_Aggregate()中一个临时变量。

上面的代码流程表明,一个“(内部的)聚合接口”至少具有拥有如下信息:
  - 一个Interfaces对象。用于存放所有实现过的接口列表;
  - 在_Interface()中的Interfaces与foo的对照表“$Aggrs与$Aggri”中存放一对信息。用于实
    现getAggrInterfaces()函数,并用于支持QueryInterface()对该函数foo的查询;
  - 在实现接口的函数内部,持有Interfaces对象的一个引用。它用于各接口的实现。

五、其它
~~~~~~~~~~~~~~~~~~

1. 缺省注册的接口
  ----------
Qomo为的一些全局对象、函数和基类注册了缺省的接口。这些接口定义在Interface.js中。缺
省注册的对象包括:
  注册到        接口             说明
  --------------------------------------------------------------------
  *             IInterface       包括undefined、null在内的所有JS原生对象和Qomo对象等
  $import()     IImport          (beta版暂未实现)
  MuEvent()     IMuEvent         所有多投事件句柄: 由MuEvent()构造的实例(beta版暂未实现)
  JoPoint()     IJoPoint         所有的联接点: 由JoPoint()构造的实例
  TObject()     IObject          Qomo OOP系统的基类
  TClass        IClass           所有通过Class()注册的类
  Class()       IClassRegister   类注册函数
  Class()等     IJoPoints        Qomo内部为一些能提供AOP能力的函数注册了IJoPoints接口
  Aspect()      IAspect          Qomo AOP系统的切面基类

2. 如何为特定的对象(如JavaScript原生对象)注册接口
  ----------
  在Qomo的(目前的)发布版本中,对一些JavaScript原生对象未提供接口支持。例如对Array()对象。
这只是因为Qomo没有觉察到这样做的必要,因而没有加入相关的代码。这在技术实现上其实非常简
单。下面参考对MuEvent()的实现,介绍一下Array()的接口实现方法:
---------------
// 以下代码填写在interface.js中

// 1. 接口声明
IArray = function() {
  this.push = Abstract;
  this.pop = Abstract;
  // ...
}

// 2. Interface()的实现代码中,warpInterface()函数声明之后加入代码
warpInterface(IArray);

// 3. 在isImplemented()的实现代码中,修改(添加)如下代码
switch (intf) {
  // ...
  case IArray:   return this instanceof Array;
}
---------------
这样就完成了。

3. 将来的版本
  ----------
  可能在更晚些的版本中,Qomo会提供“聚合”、“包含”和“委托”这些技术的完整、具体的实
现(例如提供工具函数)。但目前的版本中,只提供了对“(内部的)聚合接口”这种需求的解决方法。

在Qomo V1正式发布的版本中,将包含对接口中的get/setter的实现。目前用户仍然只能使用类似于
intf.getLength()这样的方法去访问特性(attribute)。除此之外,接口中的“索引指示器”仍在考
虑之中。

与C#等高级语言一样,Qomo的接口对“方法、属性、索引指示器和事件”做出了思考或者实现,但
不支持对“常量、域、操作符、构造函数或析构函数”这些进行接口声明。这是“接口”本身的语
义所决定的。

转载于:https://www.cnblogs.com/encounter/archive/2006/04/17/2188703.html

Qomolangma实现篇(七):Qomo的接口机制相关推荐

  1. 【JavaSe】面向对象篇(七) 接口

    JavaSe·面向对象篇(七) 接口 1. 接口概述 接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量.构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法 ...

  2. 后端思想篇:设计好接口的36个锦囊!

    前言 大家好,我是捡田螺的小男孩.作为后端开发,不管是什么语言,Java.Go还是C++,其背后的后端思想都是类似的.后面打算出一个后端思想的技术专栏,主要包括后端的一些设计.或者后端规范相关的,希望 ...

  3. Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧...

    第六章 Android绘图机制与处理技巧 1.屏幕尺寸信息 屏幕大小:屏幕对角线长度,单位"寸": 分辨率:手机屏幕像素点个数,例如720x1280分辨率: PPI(Pixels ...

  4. Java进阶篇(一)——接口、继承与多态

    前几篇是Java的入门篇,主要是了解一下Java语言的相关知识,从本篇开始是Java的进阶篇,这部分内容可以帮助大家用Java开发一些小型应用程序,或者一些小游戏等等. 本篇的主题是接口.继承与多态, ...

  5. java提高篇之抽象类与接口

    转载自 java提高篇之抽象类与接口 接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的 ...

  6. [总结]-第七章 虚拟机类加载机制

    2019独角兽企业重金招聘Python工程师标准>>> [总结]-第七章 虚拟机类加载机制 常见操作 1.查看class二进制内容 hexdump -C demo.class 2.打 ...

  7. 计算机电池电源转换,图吧小白教程 篇七十七:只需一步,延长MACBOOK电池寿命(硬改电源)...

    图吧小白教程 篇七十七:只需一步,延长MACBOOK电池寿命(硬改电源) 2020-04-17 11:42:40 6点赞 24收藏 4评论 创作立场声明:看来就算到了最后这世界上也只是有IBM兼容机和 ...

  8. 【Linux】ARM篇七--WDT看门狗实验

    ARM篇七--WDT看门狗实验 一.前言 二.准备工作 三.看门狗简介 四.看门狗寄存器介绍 1.看门狗结构 2.看门狗寄存器 3.WTCON寄存器 4.WTCNT寄存器 五.看门狗代码编写 1.程序 ...

  9. Java提高篇(三四)-----fail-fast机制

    Java提高篇(三四)-----fail-fast机制 在JDK的Collection中我们时常会看到类似于这样的话: 例如,ArrayList: 注意,迭代器的快速失败行为无法得到保证,因为一般来说 ...

最新文章

  1. git - 简易指南
  2. struts2 spring hibernate 原理
  3. 他不怕被拒绝_不怕被拒绝,这几大星座男追人时最有耐心
  4. 进程中的信号赋值与变量赋值
  5. 关于公司没有公网IP也没有动态IP,如何远程办公呢?
  6. python3判断字典、列表、元组为空以及字典是否存在某个key的方法
  7. 【Pyhton】随机漫步散点图
  8. c# 计算空格宽度像素_分享计算机视觉之图像处理Python之opencv
  9. 如何用matlab分析代谢,代谢流分析工具-CellNetAnalyzer
  10. Java 调用http接口
  11. field list什么意思_什么是生物信息学?
  12. (CVPR2019)图像语义分割(18) DANet-集成双路注意力机制的场景分割网络
  13. Java的反射 基础+简单复制对象实例
  14. linux终端怎么设置monaco,ubuntu16.04安装monaco字体
  15. APICloud Studio 在海马玩模拟器上调试程序
  16. 点亮显示屏的几个重要步骤
  17. 英文投稿时图片的处理方法
  18. 微信支付的支付金额计算
  19. 南都娱乐周刊否认爆料文章出轨因与其有私人恩怨
  20. 非侵入式负荷分解之BLUED数据集

热门文章

  1. Python format 格式化函数
  2. DSP集成开发工具CCS的Git工具使用说明(二)
  3. 给小白图示讲解OFDM的原理
  4. 如何防止ISE综合时信号不被优化掉
  5. 数组中只出现一次的(一个数、两个数、三个数)
  6. thinkphp3.1 mysql5.6_Thinkphp3.1 跨库连接数据库。
  7. 僵尸网络病毒之BotNet扫盲、预防及清除
  8. spyder清除控制台命令
  9. python交互界面的退出
  10. pycharm用爱发电