了解Factory构造函数代码示例-Dart

Ana*_*Roy 15 constructor dart

我对这里提到的工厂构造函数示例有些疑问(https://www.dartlang.org/guides/language/language-tour#factory-constructors)。我知道在基本级别上只有三种类型的构造函数-默认,命名和参数化。

  1. 为什么factory在这个示例中我应该完全使用?
  2. 是正在使用的命名构造函数吗?为什么呢? 工厂构造函数示例

Dav*_*ort 26

tl; dr不一定要返回类本身的实例的情况下使用工厂。用例:

  • 构造函数很昂贵,因此您想返回一个现有实例(如果可能),而不是创建一个新实例;
  • 您只想创建一个类的实例(单例模式);
  • 您想返回一个子类实例而不是类本身。

说明

Dart类可以具有生成构造函数工厂构造函数。生成构造函数是始终返回该类的新实例的函数。因此,它不使用return关键字。常见的生成构造函数的形式为:

class Person {
  String name;
  String country;

  // unnamed generative constructor
  Person(this.name, this.country);
}
var p = Person("...") // returns a new instance of the Person class
Run Code Online (Sandbox Code Playgroud)

工厂构造函数比生成构造函数具有更宽松的约束。工厂只需要返回与该类相同类型或实现其方法(即满足其接口)的实例。这可能是该类的新实例,但也可能是该类的现有实例或子类的新实例/现有实例(其子类必定具有与父类相同的方法)。工厂可以使用控制流来确定要返回的对象,并且必须使用return关键字。为了使工厂返回新的类实例,它必须首先调用生成的构造函数。

飞镖工厂解释

在您的示例中,未命名的工厂构造函数首先从一个名为的Map属性读取_cache(由于它是Static,因此存储在类级别,因此独立于任何实例变量)。如果实例变量已经存在,则将其返回。否则,将通过调用命名的生成构造函数来生成新实例Logger._internal。缓存此值,然后返回。因为生成构造函数仅接受一个name参数,所以该mute属性将始终被初始化为false,但可以使用默认的setter进行更改:

var log = Logger("...");
log.mute = true;
log.log(...); // will not print
Run Code Online (Sandbox Code Playgroud)

该术语factory暗指工厂模式,它的全部含义是允许构造函数根据提供的参数返回子类实例(而不是类实例)。Dart中此用例的一个很好的例子是抽象的HTML Element类,它定义了数十个返回不同子类的命名工厂构造函数。例如,分别Element.div()Element.li()return <div><li>element。

在此缓存应用程序中,我发现“ factory”有点用词不当,因为其目的是避免调用生成的构造函数,并且我将现实世界中的工厂视为固有的生成。也许在这里更合适的术语是“仓库”:如果某件物品已经可用,请将其从货架上取下并交付。如果没有,请致电一个新的。

这与命名构造函数有何关系?生成构造函数和工厂构造函数都可以不命名,也可以命名:

...
  // named generative
  // delegates to the default generative constructor
  Person.greek(String name) : this(name, "Greece"); 

  // named factory 
  factory Person.greek(String name) {
    return Greek(name);
  }
}

class Greek extends Person {
  Greek(String name) : super(name, "Greece");
}


Run Code Online (Sandbox Code Playgroud)

  • `你不能调用静态方法来构造类的实例` -- 但是 `static A get instance() =&gt; A();` 是做什么的,它不是返回类的实例吗? (11认同)
  • “static”可以引用类范围的方法或变量,而“factory”仅引用构造函数方法。IOW,您不能调用静态方法来构造类的实例,也不能调用工厂方法来执行除此之外的任何操作。唯一的相似之处是它们都无法访问“this”。 (7认同)
  • 那么静态和工厂有什么区别? (2认同)
  • “你不能调用静态方法来构造类的实例” - 这是误导性的,因为你可以创建返回类实例的静态方法。我认为他真正想说的是这不是静态方法的目的。一些设计模式确实使用静态方法来创建工厂,其中一些在 Dart 引入工厂关键字后基本上已经过时了(也许过时是错误的措辞;基本上你会使用内置语言构造而不是静态工厂方法) (2认同)

Mat*_*elo 25

补充戴夫的回答,此代码显示了使用工厂返回父相关类时的清晰示例。

https://codelabs.developers.google.com/codelabs/from-java-to-dart/#3看一下这段代码

您可以在此处运行此代码。https://dartpad.dartlang.org/63e040a3fd682e191af40f6427eaf9ef

进行一些更改以了解它在某些情况下的工作方式,例如单身人士。

import 'dart:math';

abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle(2);
    if (type == 'square') return Square(2);
    // To trigger exception, don't implement a check for 'triangle'.
    throw 'Can\'t create $type.';
  }
  num get area;
}

class Circle implements Shape {
  final num radius;
  Circle(this.radius);
  num get area => pi * pow(radius, 2);
}

class Square implements Shape {
  final num side;
  Square(this.side);
  num get area => pow(side, 2);
}

class Triangle implements Shape {
  final num side;
  Triangle(this.side);
  num get area => pow(side, 2) / 2;
}

main() {
  try {
    print(Shape('circle').area);
    print(Shape('square').area);
    print(Shape('triangle').area);
  } catch (err) {
    print(err);
  }
}
Run Code Online (Sandbox Code Playgroud)


Gün*_*uer 13

1)静态方法和工厂构造函数之间没有太大区别。

对于工厂构造函数,返回类型固定为类的类型,而对于静态方法,您可以提供自己的返回类型。

可以使用调用工厂构造函数new,但new在Dart 2中,该构造函数几乎与可选对象无关。

还有(工厂)构造函数支持的其他功能,如重定向(很少使用),但静态方法不支持。

使用工厂构造函数来创建类的实例而不是静态方法来使对象创建的目的更加明显可能仍然是一种好习惯。

这就是在您发布的示例中使用工厂构造函数的原因,并且可能是因为该代码最初是在Dart 1中编写的,它允许new与其他任何类一样创建记录器实例。

2)是的,这是一个命名构造函数,并且前缀_使它成为私有的命名构造函数。只能将命名构造函数设为私有,因为否则将无处添加_前缀。

它用于防止从public factory构造函数以外的任何地方创建实例。这样可以确保Logger您的应用程序中不能有多个实例。工厂构造函数仅在首次创建实例时使用,对于后续调用始终返回先前创建的实例。

  • 如果以这种方式实现,这只是一个可能的用例,而不是普遍事实。(“它是用来防止......”) (3认同)

t.a*_*mal 5

除了其他答案之外,还要考虑实例化对象顺序以及创建实例的时间:

普通构造函数中,会创建一个实例,并使用初始化列表实例化最终变量。这就是没有return声明的原因。执行构造函数时,返回实例已经固定

工厂构造函数中要返回实例由方法决定。这就是为什么它需要一个return语句以及为什么它通常会在至少一个路径中调用一个普通的构造函数。

因此,工厂所做的与静态方法所做的没有什么不同(在其他语言中通常称为getInstance()),除非您不能使用静态方法重载构造函数,但可以使用工厂方法。即工厂方法是一种隐藏以下事实的方法:您的类的用户不是调用构造函数而是调用静态方法:

// C++
MyCoolService.getInstance()

// Dart
MyCoolService()
Run Code Online (Sandbox Code Playgroud)