JJ
最近在在使用Flutter
重构以前Native
项目时,对网络库dio
进行封装的时候发现Dio
在实例的时候是 Dio
对象时,无意中发现Dio
class 时抽象类,却还能使用Dio()
构造函数实例化,这是为什么呢?查看Flutter
源码时集合对象List
, Map
定义时都是abstract class
震惊!!! why?
factory
工厂构造函数。dart
中class
的声明示例采用 官方文档 和文档描述,因文档和blog众多,此处不再赘述。
class Logger {
final String name;
bool mute = false;
static final Map _cache = {};
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
factory Logger.fromJson(Map json) {
return Logger(json['name'].toString());
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
上述代码出现的factory会在下面一起描述
三、abstract class
抽象类
dart
中的抽象类不能实例化?答案是肯定的,和其他语言一样抽象类是不能实例化.
那下面代码该如何解释呢?
Map map = Map();
追踪一下Map
的定义
// from: DartPackage/sky_engine/core/main.dart
...
/// Creates an empty [LinkedHashMap].
abstract class Map {
external factory Map();
...
}
Map
定义的修饰符是abstract
,为什么可以通过构造函数实例化?Map
类似的还有List
, 此处以Map
为例external
和 facotry
又是啥意思,是他们影响的吗?顺着这个线索我们去一探究竟。9.4 External Functions externalFunctions
An external function is a function whose body is provided separately from its
declaration. An external function may be a top-level function (19), a method
(10.2, 10.8), a getter (10.3), a setter (10.4), or a non-redirecting constructor
(10.7.1, 10.7.2). External functions are introduced via the built-in identifier
external (17.38) followed by the function signature.
文档索引
JJ
的理解:external
:编译标识,关键字主要作用是:将声明和实现分开。external
函数呢可能是一个顶级函数,或者方法,或者一个getter
, 一个setter
又或者非重定向的构造函数
。巴拉巴拉这么多,表明这个关键字
是用来定义声明
的。后面呢主要是说明,是用来解决 dart.vm
在浏览器和客户端和服务端平台的不同实现而引入的。我这个又是废话了,嗯,那我们来顺着这个线索来找一下这个Map
的body
(实现)!
根据线索,我们知道了,Map()
创建了一个/// Creates an empty [LinkedHashMap].
然后我们就从
LinkedHashMap
入手,还有文档提供的这是关于dart.vm
来的,所以只能去瞅瞅sdk
了。IDE 打开sdk
全局搜索吧。
万幸搜索的结果不是很多,就一个一个的去看吧,先到第一个文件中去看。篇幅有限,只截取代码片段,
@patch
class LinkedHashMap {
@patch
factory LinkedHashMap(
...
if (isValidKey == null) {
if (hashCode == null) {
if (equals == null) {
return new _InternalLinkedHashMap();
}
hashCode = _defaultHashCode;
} else {
if (identical(identityHashCode, hashCode) &&
identical(identical, equals)) {
return new _CompactLinkedIdentityHashMap();
}
...
_InternalLinkedHashMap
和 _CompactLinkedIdentityHashMap
对象。path
的主要功能是和external
关联的注解。
目录为 ur flutter sdk path/bin/cache/dart-sdk/lib/_internal/vm/bin/compact_hash.dart
// VM-internalized implementation of a default-constructed LinkedHashMap.
@pragma("vm:entry-point")
class _InternalLinkedHashMap extends _HashVMBase
with
MapMixin,
_HashBase,
_OperatorEqualsAndHashCode,
_LinkedHashMapMixin
implements LinkedHashMap {
_InternalLinkedHashMap() {
_index = _uninitializedIndex;
_hashMask = _HashBase._UNINITIALIZED_HASH_MASK;
_data = _uninitializedData;
_usedData = 0;
_deletedKeys = 0;
}
abstract
抽象类中 factory
构造函数返回的instance
实例,是来自于实现类
(暂且将abstract 类看作interface
,dart
中并不包含interface
关键字)._CompactLinkedIdentityHashMap
探索过程同理.
由于抽象类factory
工厂构造函数的作用,返回了实现类实例的实例。
官方文档描述的:factory
构造函数中返回instance
实例并不是都是从本实现类创建新的,可能来自于缓存,也就是章节二中表示的;也可能来自于子类。
factory
用于单例模式的创建。class Person {
factory Person() => _instance;
Person._internal();
static final Person _instance = Person._internal();
}
Dio
中的思路dio
库代码Dio
的设计思路。
DioForBrowser
,DioForNative
移动端
和网页端
的支持用了比较巧妙的入口判断
详情请参考注释部分...
// 入口判断代码
import 'entry_stub.dart'
if (dart.library.html) 'entry/dio_for_browser.dart'
if (dart.library.io) 'entry/dio_for_native.dart';
abstract class Dio {
factory Dio([BaseOptions? options]) => createDio(options);
....
}