简体   繁体   English

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

[英]Understanding Factory constructor code example - Dart

I have some niggling questions about factory constructors example mentioned here ( https://www.dartlang.org/guides/language/language-tour#factory-constructors ).我对此处提到的工厂构造函数示例有一些琐碎的问题( https://www.dartlang.org/guides/language/language-tour#factory-constructors )。 I am aware of only three types of constructors on a basic level - default, named and parameterised.我只知道基本级别的三种构造函数——默认、命名和参数化。

  1. Why should I use factory at all for this example?为什么我应该在这个例子中使用factory
  2. Is that a named constructor which is being used?那是一个正在使用的命名构造函数吗? and why?为什么? 示例工厂构造函数

tl;dr Use a factory in situations where you don't necessarily want to return a new instance of the class itself. tl;dr在您不一定要返回类本身的实例的情况下使用工厂。 Use cases:用例:

  • the constructor is expensive, so you want to return an existing instance - if possible - instead of creating a new one;构造函数很昂贵,所以你想返回一个现有的实例——如果可能的话——而不是创建一个新实例;
  • you only ever want to create one instance of a class (the singleton pattern);你只想创建一个类的一个实例(单例模式);
  • you want to return a subclass instance instead of the class itself.你想返回一个子类实例而不是类本身。

Explanation解释

A Dart class may have generative constructors or factory constructors. Dart 类可能具有生成构造函数工厂构造函数。 A generative constructor is a function that always returns a new instance of the class.生成构造函数是一个总是返回类的新实例的函数。 Because of this, it does not utilize the return keyword.因此,它不使用return关键字。 A common generative constructor is of the form:常见的生成构造函数具有以下形式:

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

A factory constructor has looser constraints than a generative constructor.工厂构造函数比生成构造函数具有更宽松的约束。 The factory need only return an instance that is the same type as the class or that implements its methods (ie satisfies its interface).工厂只需要返回一个与该类类型相同或实现其方法(即满足其接口)的实例。 This could be a new instance of the class, but could also be an existing instance of the class or a new/existing instance of a subclass (which will necessarily have the same methods as the parent).可以是该类的新实例,但也可以是该类的现有实例或子类的新/现有实例(必须具有与父类相同的方法)。 A factory can use control flow to determine what object to return, and must utilize the return keyword.工厂可以使用控制流来确定返回什么对象,并且必须使用return关键字。 In order for a factory to return a new class instance, it must first call a generative constructor.为了让工厂返回一个新的类实例,它必须首先调用生成构造函数。

飞镖工厂解释

In your example, the unnamed factory constructor first reads from a Map property called _cache (which, because it is Static , is stored at the class level and therefore independent of any instance variable).在您的示例中,未命名的工厂构造函数首先从名为_cache的 Map 属性中读取(由于它是Static ,因此存储在类级别,因此独立于任何实例变量)。 If an instance variable already exists, it is returned.如果实例变量已经存在,则返回它。 Otherwise, a new instance is generated by calling the named generative constructor Logger._internal .否则,将通过调用命名的生成构造函数Logger._internal生成一个新实例。 This value is cached and then returned.该值被缓存然后返回。 Because the generative constructor takes only a name parameter, the mute property will always be initialized to false, but can be changed with the default setter:因为生成构造函数只接受一个name参数,所以mute属性将始终初始化为 false,但可以使用默认设置器进行更改:

var log = Logger("...");
log.mute = true;
log.log(...); // will not print

The term factory alludes to the Factory Pattern, which is all about allowing a constructor to return a subclass instance (instead of a class instance) based on the arguments supplied. factory一词指的是工厂模式,即允许构造函数根据提供的参数返回子类实例(而不是类实例)。 A good example of this use case in Dart is the abstract HTML Element class , which defines dozens of named factory constructor functions returning different subclasses. Dart 中这个用例的一个很好的例子是抽象的 HTML Element 类,它定义了几十个返回不同子类的命名工厂构造函数。 For example, Element.div() and Element.li() return <div> and <li> elements, respectively.例如, Element.div()Element.li()分别返回<div><li>元素。

In this caching application, I find "factory" a bit of a misnomer since its purpose is to avoid calls to the generative constructor, and I think of real-world factories as inherently generative.在这个缓存应用程序中,我发现“工厂”有点用词不当,因为它的目的是避免调用生成构造函数,而且我认为现实世界的工厂本质上是生成的。 Perhaps a more suitable term here would be "warehouse": if an item is already available, pull it off the shelf and deliver it.也许这里更合适的术语是“仓库”:如果某件商品已经可用,请将其从货架上取下并交付。 If not, call for a new one.如果没有,请调用一个新的。

How does all this relate to named constructors?所有这些与命名构造函数有何关系? Generative and factory constructors can both be either unnamed or named:生成构造函数和工厂构造函数都可以是未命名的或已命名的:

...
  // 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");
}


  1. There is not much difference between a static method and a factory constructor.静态方法和工厂构造函数之间没有太大区别。

    For a factory constructor the return type is fixed to the type of the class while for a static method you can provide your own return type.对于工厂构造函数,返回类型固定为类的类型,而对于静态方法,您可以提供自己的返回类型。

    A factory constructor can be invoked with new , but that became mostly irrelevant with optional new in Dart 2.可以使用new调用工厂构造函数,但这与 Dart 2 中的可选new几乎无关。

    There are other features like redirects rather rarely used that are supported for (factory) constructors but not for static methods.还有其他一些功能,例如很少使用的重定向,它们受(工厂)构造函数支持,但不支持静态方法。

    It is probably still good practice to use a factory constructor to create instances of classes instead of static methods to make the purpose of object creation more obvious.使用工厂构造函数而不是静态方法来创建类的实例可能仍然是一个好习惯,以使创建对象的目的更加明显。

    This is the reason a factory constructor is used in the example you posted and perhaps because the code was originally written in Dart 1 where it allowed to create a logger instance with new like with any other class.这就是在您发布的示例中使用工厂构造函数的原因,也许是因为代码最初是在 Dart 1 中编写的,它允许像任何其他类一样使用new创建一个记录器实例。

  2. Yes this is a named constructor and the prefix _ makes it a private named constructor.是的,这是一个命名构造函数,前缀_使其成为私有命名构造函数。 Only named constructors can be made private because otherwise there would be no place to add the _ prefix.只有命名的构造函数可以设为私有,否则就没有地方可以添加_前缀。

    It is used to prevent instance creation from anywhere else than from the public factory constructor.它用于防止从公共工厂构造函数以外的任何地方创建实例。 This way it is ensured there can't be more than one Logger instance in your application.这样可以确保您的应用程序中不会有多个Logger实例。 The factory constructor only creates an instance the first time, and for subsequent calls always returns the previously created instance.工厂构造函数只在第一次创建一个实例,后续调用总是返回先前创建的实例。

Complementing Dave's answer, this code shows a clear example when use factory to return a parent related class.作为对 Dave 答案的补充,此代码显示了使用工厂返回父相关类时的清晰示例。

Take a look a this code from https://codelabs.developers.google.com/codelabs/from-java-to-dart/#3https://codelabs.developers.google.com/codelabs/from-java-to-dart/#3查看这段代码

You can run this code here.您可以在此处运行此代码。 https://dartpad.dartlang.org/63e040a3fd682e191af40f6427eaf9ef https://dartpad.dartlang.org/63e040a3fd682e191af40f6427eaf9ef

Make some changes in order to learn how it would work in certain situations, like singletons.进行一些更改以了解它在某些情况下的工作方式,例如单身人士。

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);
  }
}

In addition to the other answers, also consider the order of instantiating objects and when the instance is created:除了其他答案之外,还要考虑实例化对象的顺序以及创建实例的时间:

In normal constructor , an instance gets created and the final variables get instantiated with the initializer list.普通构造函数中,创建一个实例,并使用初始化列表实例化最终变量。 This is why there's no return statement.这就是为什么没有return语句的原因。 The instance to return is already fixed , when executing the constructor!执行构造函数时,要返回的实例已经固定

In a factory constructor , the instance to return is decided by the method .工厂构造函数中,要返回的实例由方法决定 That's why it needs a return statement and why it'll usually call a normal constructor in at least one path.这就是为什么它需要一个return语句以及为什么它通常会在至少一个路径中调用普通构造函数的原因。

So a factory does nothing different than a static method could do (in other languages often called getInstance() ), except you cannot overload the constructor with a static method but you can with a factory method.因此,工厂所做的与静态方法所做的没有什么不同(在其他语言中通常称为getInstance() ),除了您不能使用静态方法重载构造函数但可以使用工厂方法。 Ie factory methods are a way to hide the fact that the user of your class is not calling a constructor but a static method:即工厂方法是一种隐藏类的用户不是调用构造函数而是调用静态方法这一事实的方法:

// C++
MyCoolService.getInstance()

// Dart
MyCoolService()

I have some niggling questions about factory constructors example mentioned here ( https://www.dartlang.org/guides/language/language-tour#factory-constructors ).我对这里提到的工厂构造函数示例有些疑问( https://www.dartlang.org/guides/language/language-tour#factory-constructors )。 I am aware of only three types of constructors on a basic level - default, named and parameterised.在基本级别上,我只知道三种类型的构造函数-默认,命名和参数化。

  1. Why should I use factory at all for this example?为什么在这个例子中我应该完全使用factory
  2. Is that a named constructor which is being used?那是一个正在使用的命名构造函数吗? and why?为什么呢? 工厂构造函数示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM