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这个,暂时搁浅。

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


  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值