Last active
November 27, 2019 13:04
-
-
Save talamaska/c728833a8859614c6e1e0c40b8e3f361 to your computer and use it in GitHub Desktop.
Constructors in Dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Robot { | |
Robot(); | |
} | |
// or if no arguments | |
class Robot { | |
} | |
// normal instanciation | |
var robot = Robot(); | |
class Robot { | |
double height; | |
Robot(height) : this.height = height; | |
} | |
class Robot { | |
double height; | |
Robot(data) : this.height = data.physics.raw['heightInFt']; | |
} | |
//short cut | |
class Robot { | |
double height; | |
Robot(this.height); | |
} | |
// instanciation with param | |
var r = Robot(5); | |
// instanciation with param that is an Object like | |
var r = Robot(myData); | |
class Robot { | |
static mToFt(m) => m * 3.281; | |
double height; // in ft | |
Robot(height) : this.height = mToFt(height); | |
} | |
// extending | |
class Machine { | |
String name; | |
Machine(this.name); | |
} | |
class Robot extends Machine { | |
static mToFt(m) => m * 3.281; | |
double height; | |
Robot(height, name) : this.height = mToFt(height), super(name); | |
} | |
// adding guards | |
class Robot { | |
final double height; | |
Robot(height) : this.height = height, assert(height > 4.2); | |
} | |
// simple example | |
class Robot { | |
double height; | |
Robot(this.height); | |
} | |
main() { | |
var r = Robot(5); | |
print(r.height); // 5 | |
} | |
// you can reassign value to the height | |
main() { | |
var r = Robot(5); | |
r.height = 6; | |
print(r.height); // 6 | |
} | |
// that way you make the param private and expose a public getter | |
class Robot { | |
double _height; | |
Robot(this._height); | |
get height { | |
return this._height; | |
} | |
} | |
// or simpler | |
class Robot { | |
double _height; | |
Robot(this._height); | |
get height => _height; | |
} | |
// full equivalend of the first robot | |
class Robot { | |
double _height; | |
Robot(this._height); | |
get height => _height; | |
set height(value) => _height = value; | |
} | |
// not possible to use setters as param to the constructor | |
class Robot { | |
double _height; | |
Robot(this.height); // ERROR: 'height' isn't a field in the enclosing class | |
get height => _height; | |
set height(value) => _height = value; | |
} | |
// use the setter in the constructor body | |
class Robot { | |
double _height; | |
Robot(h) { | |
height = h; | |
} | |
get height => _height; | |
set height(value) => _height = value; | |
} | |
// named arguments | |
class Robot { | |
final double height; | |
final double weight; | |
final List<String> names; | |
Robot({ this.height, this.weight, this.names }); | |
} | |
main() { | |
final r = Robot(height: 5, names: ["Walter"]); | |
print(r.height); // 5 | |
} | |
// adding guards to named arguments constructors | |
class Robot { | |
final double height; | |
final double weight; | |
final List<String> names; | |
Robot({ this.height, @required this.weight, this.names }); | |
} | |
// or | |
class Robot { | |
final double height; | |
final double weight; | |
final List<String> names; | |
Robot({ this.height, this.weight, this.names }) : assert(weight != null); | |
} | |
// cannot make positional params private | |
class Robot { | |
final double _height; | |
final double _weight; | |
final List<String> _names; | |
Robot({ this._height, this._weight, this._names }); // ERROR: Named optional parameters can't start with an underscore | |
} | |
// this works | |
class Robot { | |
final double _height; | |
final double _weight; | |
final List<String> _names; | |
Robot({ height, weight, names }) : _height = height, _weight = weight, _names = names; | |
get height => _height; | |
get weight => _weight; | |
get names => _names; | |
} | |
// or even with default values | |
class Robot { | |
final double _height; | |
final double _weight; | |
final List<String> _names; | |
Robot({ height, weight, names }) : _height = height ?? 7, _weight = weight, _names = names; | |
get height => _height; | |
get weight => _weight; | |
get names => _names; | |
} | |
main() { | |
print(Robot().height); // 7 | |
} | |
// using public keys looks better | |
class Robot { | |
final double height; | |
final double weight; | |
final List<String> names; | |
Robot({ this.height = 7, this.weight = 100, this.names = const [] }); | |
} | |
main() { | |
print(Robot().weight); // 100 | |
} | |
// Both positional and named argument styles can be used together: | |
class Robot { | |
final double _height; | |
final double _weight; | |
final List<String> _names; | |
Robot(height, { weight, names }) : | |
_height = height, | |
_weight = weight, | |
_names = names; | |
get height => _height; | |
get weight => _weight; | |
} | |
main() { | |
var r = Robot(7, weight: 120); | |
print(r.height); // 7 | |
print(r.weight); // 120 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Positional optional parameters | |
// Wrap the optional parameter with [ ] square brackets. | |
class User { | |
String name; | |
int age; | |
String home; | |
User(this.name, this.age, [this.home = 'Earth']); | |
} | |
User user1 = User('Bob', 34); | |
User user2 = User('Bob', 34, 'Mars'); | |
// Named optional parameters | |
// Wrap the optional parameter with { } curly braces. | |
class User { | |
String name; | |
int age; | |
String home; | |
User(this.name, this.age, {this.home = 'Earth'}); | |
} | |
User user1 = User('Bob', 34); | |
User user2 = User('Bob', 34, home: 'Mars'); | |
// Note | |
// If you need private fields then you can use [] square brackets: | |
class User { | |
int _id; | |
User([this._id]); | |
} | |
User user = User(3); | |
// or do as the accepted answer says and use an initializer list: | |
class User { | |
int _id; | |
User({int id}) | |
: _id = id; | |
} | |
User user = User(id: 3); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// that's why we have named constructors | |
class Robot { | |
final double height; | |
Robot(this.height); | |
Robot.fromPlanet(String planet) : height = (planet == 'geonosis') ? 2 : 7; | |
Robot.copy(Robot other) : this(other.height); | |
} | |
// What happened in copy? We used this to call the default constructor, effectively "redirecting" the instantiation. | |
main() { | |
print(Robot.copy(Robot(7)).height); // 7 | |
print(Robot.fromPlanet('geonosis').height); // 2 | |
print(Robot.fromPlanet('earth').height); // 7 | |
} | |
// with inheritance | |
class Machine { | |
String name; | |
Machine(); | |
Machine.named(this.name); | |
} | |
class Robot extends Machine { | |
final double height; | |
Robot(this.height); | |
Robot.named({ height, name }) : this.height = height, super.named(name); | |
} | |
main() { | |
print(Robot.named(height: 7, name: "Walter").name); // Walter | |
} | |
// you may want to keep private the default constructor and expose only named ones | |
// We can make a constructor private by prefixing it with an underscore: | |
class Robot { | |
Robot._(); | |
} | |
// you can call a private constructor from a named one | |
class Machine { | |
String name; | |
Machine._(); | |
Machine.named(this.name); | |
} | |
class Robot extends Machine { | |
final double height; | |
Robot._(this.height, name) : super.named(name); | |
Robot.named({ height, name }) : this._(height, name); | |
} | |
main() { | |
print(Robot.named(height: 7, name: "Walter").name); // Walter | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Factory constructors are syntactic sugar for the “factory pattern”, usually implemented with static functions. | |
// They appear like a constructor from the outside (useful for example to avoid breaking API contracts), | |
// but internally they can delegate instance creation invoking a “normal” constructor. | |
// This explains why factory constructors do not have initializers. | |
// Since factory constructors can return other instances (so long as they satisfy the interface of the current class), | |
// we can do very useful things like: | |
// * caching: conditionally returning existing objects (they might be expensive to create) | |
// * subclasses: returning other instances such as subclasses | |
// They work with both normal and named constructors! | |
class Robot { | |
final double height; | |
Robot._(this.height); | |
factory Robot() { | |
return Robot._(7); | |
} | |
} | |
main() { | |
print(Robot().height); // 7 | |
} | |
// Here’s our robot warehouse, that only supplies one robot per height: | |
class Robot { | |
final double height; | |
static final _cache = <double, Robot>{}; | |
Robot._(this.height); | |
factory Robot(height) { | |
return _cache[height] ??= Robot._(height); | |
} | |
} | |
main() { | |
final r1 = Robot(7); | |
final r2 = Robot(7); | |
final r3 = Robot(9); | |
print(r1.height); // 7 | |
print(r2.height); // 7 | |
print(identical(r1, r2)); // true | |
print(r3.height); // 9 | |
print(identical(r2, r3)); // false | |
} | |
// Finally, to demonstrate how a factory would instantiate subclasses, | |
// let’s create different robot brands that calculate prices as a function of height: | |
abstract class Robot { | |
factory Robot(String brand) { | |
if (brand == 'fanuc') return Fanuc(2); | |
if (brand == 'yaskawa') return Yaskawa(9); | |
if (brand == 'abb') return ABB(7); | |
throw "no brand found"; | |
} | |
double get price; | |
} | |
class Fanuc implements Robot { | |
final double height; | |
Fanuc(this.height); | |
double get price => height * 2922.21; | |
} | |
class Yaskawa implements Robot { | |
final double height; | |
Yaskawa(this.height); | |
double get price => height * 1315 + 8992; | |
} | |
class ABB implements Robot { | |
final double height; | |
ABB(this.height); | |
double get price => height * 2900 - 7000; | |
} | |
main() { | |
try { | |
print(Robot('fanuc').price); // 5844.42 | |
print(Robot('abb').price); // 13300 | |
print(Robot('flutter').price); | |
} catch (err) { | |
print(err); // no brand found | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The factory constructor Robot(height) simply always returns the one and only instance that was created | |
when loading the Robot class. | |
class Robot { | |
static final Robot _instance = Robot._(7); | |
final double height; | |
factory Robot() { | |
return _instance; | |
} | |
Robot._(this.height); | |
} | |
main() { | |
var r1 = Robot(); | |
var r2 = Robot(); | |
print(identical(r1, r2)); // true | |
print(r1 == r2); // true | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment