在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这个,暂时搁浅。
我这个是边写边研究,所以没有什么深度,而且到点下班了,上面那个问题也就搁浅了。