IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Flutter factory关键字 -> 正文阅读

[移动开发]Flutter factory关键字

在Flutter中好几次见到factory,以前不耽误我使用,也就没太关注,但是今天有看到了,所以就想知道他是干啥的。

我在百度中搜索“Flutter factory关键字”,基本上就两篇博客,剩下的就是互相摘抄,也没说个所以然来,所以我就更好奇了,我一片一片博客的看过去,仍然看不出新意。

dart中factory关键词的使用
flutter 中factory(构造方法上的唯一对象) 与单例模式

有这么一句话:
当你需要构造函数不是每次都创建一个新的对象时,使用factory关键字

然后给出的实例:

class Manager {
  // 工厂模式 : 单例公开访问点
  factory Manager() => _getInstance();

  static Manager get instance => _getInstance();

  // 静态私有成员,没有初始化
  static Manager _instance;

  // 私有构造函数
  Manager._internal() {
    // 初始化
  }

  // 静态、同步、私有访问点
  static Manager _getInstance() {
    if (_instance == null) {
      _instance = new Manager._internal();
    }
    return _instance;
  }
}

main() {
  // 无论如何初始化,取到的都是同一个对象
  Manager manager1 = new Manager();
  Manager manager2 = Manager.instance;
  Manager manager3 = new Manager();
  Manager manager4 = Manager.instance;
  print(identical(manager1, manager2)); //true
  print(identical(manager1, manager3)); //true
  print(identical(manager3, manager4)); //true
}

然后另外一片博客:

class Singleton {
  static final Singleton _singleton = Singleton._internal();

  factory Singleton() {
    return _singleton;
  }
  
  Singleton._internal();
}

main() {
  var s1 = Singleton();
  var s2 = Singleton();
  print(identical(s1, s2));  
}

两段代码对比起来就是第一段多了点,然后在使用上做了优化,但是看一针见血的还是第二段代码;
还是看那句话:
当你需要构造函数不是每次都创建一个新的对象时,使用factory关键字

第一段代码看一下factory的使用地方,是调用了_getInstance()方法,然后_getInstance()方法里面就是一个是否初始化的判断,没有就调用一下构造函数,也就是在这里调用了一次私有构造函数;整个流程看下来,没看到factory起到的作用;
它对外的使用就是通过内部调用_getInstance()方法,而_getInstance()方法内部的初始化从始至终也就只做了一次。

而第二段代码比较直接,一个私有构造函数,一个对外公开构造方法,初始化就只有调用对外的factory修饰的公开构造方法,不管调用多少次,始终都返回的是那一个静态初始化好的变量,那这样的话我就直接调用那个静态变量就好了,factory又起到了什么作用呢。

当你需要构造函数不是每次都创建一个新的对象时,使用factory关键字

按照那句话最直接的理解就是:

class SingleInstance{

  factory SingleInstance(){};

}

main(){
	val s1=SingleInstance();
	val s2=SingleInstance();
	//理论上s1==s2
}

但是观察到没有这种写法,factory修饰的构造方法必须得有对应的构造函数返回值。那换句话说,就是返回值需要具有唯一性来保证它的单例,而不是factory修饰的构造方法具有唯一性;

所以总结性的来说,就是factory是用来修饰公开构造方法名的(我尝试改个名字,发现不允许),然后他带有一个返回值;它的意义就是让构造方法变成一个带有返回值的方法,于是返回值就具有很大的操作空间;在某种程度上来讲,这个修饰的方法已经不是构造方法了,它就是一个带有构造方法证件的皮包方法(带返回值的),且返回值类型也固定为该类类型(以及子类)实例;

这是我捕获到的第一种方法,用来做单例,以这种特殊取巧性来做单例,我换一种方式也能做:

class SingleInstance {
  static final SingleInstance _singleInstance = SingleInstance._internal();

  static SingleInstance get singleton => _singleInstance;

  SingleInstance._internal();
}

  void mian() {
    var s1 = SingleInstance.singleton;
    var s2 = SingleInstance.singleton;
    //s1==s2也是成立的
  }

所以factory只是表明他有那个带返回值的特性且死死的绑定了构造函数,所以有构造函数的单一性特征。

换成下面这种写法就啥也不是:

class SingleInstance {
  static final SingleInstance _singleInstance = SingleInstance._internal();

  //static SingleInstance get singleton => _singleInstance;

  factory SingleInstance(){
    return SingleInstance._internal();
  }

  SingleInstance._internal();
}
  void mian() {
    var s1 = SingleInstance();
    var s2 = SingleInstance();
    //s1==s2是不成立的
  }

第一篇文章一共展示了三种场景,单例是一种,还有一个缓存实例,它的作用效果等同于单例,不过是用一个Map根据入参的不同而构造多个实例,但是入参相同的话就在获取时返回同一个实例,这个也只是展示了一种使用场景,没有特殊性;

还有一个是工厂模式,抛开工厂模式,当你实例化一个指定类名的类时,返回的就是你指定的那个类的实例,不会是子类的实例;单纯看实例化,实例的就是类本身;而factory因为有返回值且返回值是类以及子类的实例,所以在初始化的时候可以写着父类的名字初始化子类;

写到这本来我以为再加上一句:凡是返回的引用仍然受父类的限制就结束了;但是我改了一点东西;

本来的例子是:

abstract class Animal {
  String name;
  void getNoise();
  factory Animal(String type,String name) {
    switch(type) {
      case "cat":
        return new Cat(name);
      case "dog":
        return new Dog(name);
      default:
        throw "The '$type' is not an animal";
    }
  }
}

class Cat implements Animal {
  String name;
  Cat(this.name);
  @override
  void getNoise() {
    print("${this.name}: mew~");
  }
}

class Dog implements Animal {
  String name;
  Dog(this.name);
  @override
  void getNoise() {
    print("${this.name}: wang~");
  }
}

int main(){
  var cat = new Animal("cat","wiki");
  var dog = new Animal("dog","baobao");
  cat.getNoise();
  dog.getNoise();
  return  0;
}

结合我上面说的,这里返回的cat和dog真实的实例应该是对应的Cat和Dog;我按照Java的思想,父类引用指向子类对象;那cat和dog就应该是Animal的引用,只不过实例是具体对应的类型;
我改了一点东西;

class Dog implements Animal {
  String name;
  Dog(this.name);
  @override
  void getNoise() {
    print("${this.name}: wang~");
  }
  void wang(){
  	print("--------wang--------");
  }
}

int main(){
  var cat = new Animal("cat","wiki");
  Dog dog = new Animal("dog","baobao");
  cat.getNoise();
  dog.getNoise();
  dog.wang();
  return  0;
}

在Dog类中我增加了一个wang()方法,在main函数中,我把dog指向的引用直接指向了Dog,然后调用了wang()方法,它正确执行了。。。。

现在的代码从表面上看上去就是子类引用指向父类实例的样子(当然我们知道直接上返回的就是子类实例)。

但是怎么看怎么别扭,我甚至以为Dart就是存在子类引用指向父类实例的性质的。

我赶紧重新写了个正常的例子

class Parent {

}

class Child extends Parent{
  void main(){
    Child child = new Parent();
  }
}

看到代码上明晃晃的红线报错不允许这么干的时候,我才松了一口气。

本来学习就是一个爬上坡路的过程,你还没到半山腰呢,结果别人告诉你:你看到的山顶并不是山顶,上山和下山完全就不是一条路。

再看那个特殊的例子,发现就连抽象类的继承都不是extends关键字,而是implements,这不是接口的写法么。

当我改成extends时,给出如下报错:

The class ‘Cat’ cannot extend ‘Animal’ because ‘Animal’ only has factory constructors (no generative constructors), and ‘Cat’ has at least one generative constructor.
Try implementing the class instead, adding a generative (not factory) constructor to the superclass Cat, or a factory constructor to the subclass.

其中一个修改意见就是改为implements。

补充一个知识点,就是Dart的抽象类和接口是同一种写法,都是abstract。

以上总结起来就是:

factory就是专门用来修饰构造函数,而且它的特性就是带返回值,返回值类型就是修饰的类或子类;可以利用这一特性在不同的场景去实现自己想要的。

另外一个特性就是上面没说完的,但是我也没研究明白,就是implements这个,暂时搁浅。

我这个是边写边研究,所以没有什么深度,而且到点下班了,上面那个问题也就搁浅了。


  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-02 11:30:10  更:2021-09-02 11:32:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/31 6:05:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码