How to properly use Dart encapsulation in inheritance - dart

Encapsulation says you should use private attributes, but this brought me an issue. I cannot access super-class attributes in my sub-class. I've readed that if classes are in different files, you cannot read them if their private, so should I just use public attributes or use multiple classes in the same file? which of this fixes are commonly accepted/not considered a bad practice?
class Animal{

String? _color;
String? _specie;
int? _age;

Animal(this._color, this._specie, this._age);

}
import 'Animal.dart';

class Dog extends Animal{

bool? _rabid;

Dog(super._color, super._specie, super._age, this._rabid);

String? isRabid(){
String isRabidMsg = 'is rabid?: $_rabid';
return isRabidMsg;
}

String? sayAge(){
String sayAgeMsg = "the age is: "; //Can't access age attribute from super-class
return sayAgeMsg;
}

}
void main() {
Dog dog1 = new Dog('black', 'german shepard', 2, false);
}

You could try and use getters for the private fields
class Animal {
String? _color;
String? _specie;
int? _age;
String? get color => _color;
String? get specie => _specie;
int? get age => _age
...
}

Related

Can required parameters in a Dart constructor be named?

I am working with some Dart code for a Flutter/Dart class I'm taking. I expected the following code to compile, but it did not:
class Person {
String? name;
int? age;
Person(this.name, this.age);
#override
String toString() {
return "name: $name\nage: $age";
}
}
void main() {
final person = Person(name: 'Joe', age: 30);
print(person);
}
When I made the constructor parameters optional, as below, it does compile:
class Person {
String? name;
int? age;
Person({this.name, this.age});
#override
String toString() {
return "name: $name\nage: $age";
}
}
void main() {
final person = Person(name: 'Joe', age: 30);
print(person);
}
I tried searching the Flutter dev docs for a reason why this is so, or a way to have required parameters with their names in a constructor, but I didn't find anything. I can certainly imagine cases where I would want required constructor parameters to have names.
My pubspec.yaml specifies the following:
environment: sdk: ">=2.12.0 <3.0.0"
Your first example uses what are called "positional parameters" in dart. You cannot call a positional parameter with a name label, which is why the first example does not compile.
The second example uses "named parameters". Any parameter defined within {} is considered a named parameter and must be called using a name label. As explained in the dart language tour, named parameters are optional unless they’re explicitly marked as required.
So simply add the required keyword before any named parameter you want to require.
class Person {
String? name;
int? age;
Person({required this.name, required this.age});
#override
String toString() {
return "name: $name\nage: $age";
}
}
void main() {
final person = Person(name: 'Joe', age: 30);
print(person);
}

Nestjs: Cast complex Entity to Dto

I'm trying to cast a complex Entity to a Dto. I would like to remove some values which are in the entity from the DTO.
My entity looks like this (For simplicity a large part of the entity is omitted):
export class ResultEntity {
constructor(
public id: string,
public userId: string,
public results: CalculationOutputEntity[] = [],
public item: Item = new Item(),
) { }
}
export class Item {
constructor(
public privat: Private = new Private(),
public state: State = new State(),
public combined: number = 0,
) { }
}
export class State {
constructor(
public numberA: number = 0,
public numberB: number = 0,
public numberC: number = 0,
public numberD: number = 0,
) { }
}
I have found a solution which works very well for simple entities: Cast entity to dto
If I adopt this suggestion of the custom interceptor, removing the id or the whole item property works.
I have tried two possibilities tot define my DTOs:
It returns only the id and the item as a whole.
#Exclude()
export class AdvisoryResultDto {
#Expose()
public id: string;
public userId: string;
public results: CalculationOutputDto[];
#Expose()
public item: Item;
}
This solution returns everything except the item property.
export class AdvisoryResultDto {
public id: string;
public userId: string;
public results: CalculationOutputDto[];
#Exclude()
public item: Item;
}
The problem now is that I want to remove only certain values within the item property. So for example the private field and within the state-property numberB.
I would like to have the possibility within the nested classes to remove single values also with Exclude().
So for example:
export class AdvisoryResultDto {
public id: string;
public userId: string;
public results: CalculationOutputDto[];
public item: Item;
}
export class Item {
#Exclude()
public privat: PrivateDto;
public state: StateDto;
public combined: number;
}
export class StateDto {
public numberA: number;
#Exclude()
public numberB: number;
public numberC: number;
public numberD: number;
}
Unfortunately I can't find anything about this exact problem. To take over the mapping manually would also not be a solution, since the CalculationOutput is by far more complex and is nested with many classes and properties.
Am I just missing a small step or is it not possible with Expose and Exclude from the class-transformer? If not I would appreciate another solution.
So i found the soulution in the documentation of the class-transformer package: https://github.com/typestack/class-transformer#working-with-nested-objects
I need to add the #Type-Decorator to nested classes
The solution:
#Expose()
export class AdvisoryResultDto {
public id: string;
public userId: string;
public results: CalculationOutputDto[];
#Type(() => Item)
public item: Item;
}
export class Item {
#Exclude()
#Type(() => PrivateDto)
public privat: PrivateDto;
#Expose()
#Type(() => StateDto)
public state: StateDto;
public combined: number;
}
export class StateDto {
public numberA: number;
#Exclude()
public numberB: number;
public numberC: number;
public numberD: number;
}
Why not make a constructor and then initalize DTO with only the required values from the entity? Just pass the entity object to DTO's constructor and remove the fields from DTO.

Using mixins for private fields or abstract methods Dart

I am experimenting with Dart mixins and noticed that
You can use private fields in mixins
Even abstract methods like abstract classes.
Imagine you have few abstract methods no need to create an abstract ad extend it, you can collect them inside a mixin and re-use it.
The discussion goes whether you like to have inheritance within your design
Here is a code snippet:
import 'package:flutter/cupertino.dart';
mixin Favourite {
bool _isFavourite = false;
bool get isFavourite;
}
class ProductProvider
with Favourite, ChangeNotifier
implements Comparable<ProductProvider> {
final String id;
final String title;
final String description;
final String imageUrl;
final double price;
ProductProvider({
required this.id,
required this.title,
required this.description,
required this.imageUrl,
required this.price,
});
ProductProvider.noPrice({
required this.id,
required this.title,
required this.description,
required this.imageUrl,
bool isFavourite = false,
}) : price = 0.0;
toggleFavourite() {
this._isFavourite = !this._isFavourite;
notifyListeners();
}
#override
bool get isFavourite => _isFavourite;
factory ProductProvider.fromJSON(Map<String, dynamic> json) {
return json['price'] != null
? ProductProvider(
id: json['id'],
title: json['title'],
description: json['description'],
imageUrl: json['imageUrl'],
price:
json['price'] is int ? json['price'].toDouble() : json['price'])
: ProductProvider.noPrice(
id: json['id'],
title: json['title'],
description: json['description'],
imageUrl: json['imageUrl'],
isFavourite: json['isFavourite'] ?? false,
);
}
#override
int compareTo(ProductProvider other) {
return (price - other.price).toInt();
}
}

How to create null safe, default value constructor with Syntactic sugar

How do I create a null safe constructor with Syntactic sugar that would set a default value if the provided value is null?
class Person {
Person({
required this.name, //Idealy, adding (?? "friend") instead of "required" should've worked but doesn't.
required this.age,
});
String name;
int age;
greet() {
print("Hello $name");
}
}
So, I actually want something like this,
class Person {
Person({
this.name ?? "friend",
this.age ?? 0,
});
String name;
int age;
greet() {
print("Hello $name");
}
}
But, as you know this is not valid in dart. So, how actually, should I achieve this?
class Person {
Person({
String? name,
int? age,
}) : this.name = name ?? "friend",
this.age = age ?? 0;
String name;
int age;
void greet() {
print("Hello $name");
}
}
Constructor Optional Params
for selecting my proposal
select this as an answer (converted from comment with permission)
You can also use default values for your optional parameters:
class Person {
Person({
this.name = "friend",
this.age = 0,
});
String name;
int age;
greet() {
print("Hello $name");
}
}
The parameter is not required, and if you don't pass it, it gets the default value. If you do pass an argument, it must be non-null.

How to use this in a dart constructor with private variables

When I try to create a constructor in dart like Student(this._name) it doesn't work with private variables.
I have already tried using setters but it doesn't work either.
class Student{
var _id;
var _name;
Student(this.id, this.name);
void set id(int id) => _id = id;
void set name(String name) => _name = name;
}
This is not supported because it would expose private implementation to the outside.
If you'd rename var _id; to var _userId; you would break code that uses your class just by renaming a private field.
See instead the comment below my answer.
class Student{
var _id;
var _name;
Student({this._id, this._name}); // error
void set id(int id) => _id = id;
void set name(String name) => _name = name;
}
The alternative
class Student{
var _id;
var _name;
Student({int id, String name}) : _id = id, _name = name;
void set id(int id) => _id = id;
void set name(String name) => _name = name;
}
You can use this notation
class Student {
String _id;
String _name;
Student({required String id, required String name})
: _id = id,
_name = name;
}
Some of you maybe struggle if the class was inheritance, you just need add coma (,) after initialize your private.
Example
class Animal {
String _name;
int _age;
}
class Dog extends Animal {
String _race;
Dog(String name, int age, {String? race}) : _race = race ?? "Wild", super(name, age);
}
Hope this code can help you.
This notation is not valid because the variable is not private and its elements are just as accessible again.
DartLang says: AVOID wrapping fields in getters and setters just to be "safe".

Resources