Class in Dart/Flutter
What is class in Dart?
- In object-oriented programming, a
class
is a blueprint for creating objects (a particular data structure), providing initial values for state (member variables or attributes), and implementations of behavior (member functions or methods). - We can assume a class as a sketch (prototype) or a car. It contains all the details about model name, year, features, price, etc. Based on these properties of the car, we can build the car. Here the car is an object.
- There can be many cars so we can create many objects of cars to access all the properties.
Benefit of object-oriented programming
- Modularity: The source code of an object can be maintained individually and can hide from the other object’s source code.
- Data – hiding: Using oops programming, the details of the internal functionality of code are hidden from the others. For example – Users only interact with the application, but they don’t familiar with the internal implementation.
- Reusability: We don’t need to write the same code again and again. We can use the object of class multiple times in our program.
- Pluggability and debugging easy: If any object is creating a problem in our program, and then we can replace it in our program and plug the new object as its replacement. The oops code can be easy to debug.
Defining a Class in Dart
Dart provides class
keyword followed by a ClassName
is used to define a class; all fields and functions are enclosed by the pair of curly braces {}
.
class ClassName { <fields/properties> <getters/setters> <constructors> <functions> }
<fields/properties>
any variable declared in a class, represent data pertaining to objects.<getters/setters>
initialize and retrieve the values of the fields of a class<constructors>
responsible for allocating memory for the objects of the class.<functions>
represent actions an object can take
Creating Instance of the class
- To create an instance of the
class
, use thenew
keyword followed by the class name.
var object_name = new ClassName([arguments])
- The
new
keyword is responsible for instantiation. Starting from Dart 2, the keywordnew
can be omitted. - The right-hand side of the expression invokes the constructor.
- The constructor should be passed values if it is parameterized.
Libraries and visibility
- a library referring to the code inside a file with the
.dart
extension - to use that particular library, you have to reference its content with the
import
keyword - using the
as
keyword if have two different libraries have implemented a class with the same name - selectively import or exclude types using the
show
andhide
keywords
Class Constructors
A constructor is a special function of the class that is responsible for initializing the variables of the class. Dart defines a constructor with the same name as that of the class. A constructor is a function and hence can be parameterized. However, unlike a function, constructors cannot have a return type.
👉Named and positional parameters in Dart
Class_name(parameter_list) { //constructor body //............. }
- If your class doesn’t define a constructor, the compiler automatically adds a default constructor with no parameters and an empty body.
- The “initializing formal” using
this
keyword, more readable and it initializes the variables immediately - With null safety, a named argument with a non-nullable type must either have a default or be marked with the new
required
keyword. Otherwise, it wouldn’t make sense for it to be non-nullable, because it would default tonull
when not passed. - With the “initializing formal” you can still declare a body to perform additional setup for the class, constructors cannot have a return type.
- If you don’t declare a constructor, a default no-argument constructor is provided for you.
Initializer list
- When using the initializing formal approach, the names of the variables must match the ones declared in the constructor.
- If you wanted to keep fields private but with a different name in the constructor, use an initializer list
class Test { int _secret; double _superSecret; Test(int age, double wallet) : _secret = age, _superSecret = wallet; }
Named Constructors
Named constructors are generally used to implement a default behavior the user expects from your class. They are the only alternative to have multiple constructors since Dart has no method overload.
Class_name.constructor_name(param_list)
Redirecting constructors
Sometimes you might have a constructor that does almost the same thing already implemented by another one. It may be the case to use redirecting constructors in order to avoid code duplication.
Factory constructors
- The
factory
keyword returns an instance of the given class that’s not necessarily a new one. It can be useful when:- you want to return an instance of a subclass instead of the class itself,
- you want to implement a singleton (the Singleton pattern),
- you want to return an instance from a cache.
- Factory constructors are like
static
methods and so they don’t have access to this. There cannot be together a factory and a “normal” constructor with the same name.
static
variables and methods
- The static keyword can be applied to the data members of a class, i.e., fields and methods. A static variable retains its values till the program finishes execution. Static members are referenced by the class name.
- The static variables and methods are part of the class instead of a specific instance.
- The
static
keyword is used for a class-level variable and method that is the same for every instance of a class, this means if a data member is static, it can be accessed without creating an object. - The static keyword allows data members to persist values between different instances of a class.
- There is no need to create a class object to access a static variable or call a static method: simply put the class name before the static variable or method name to use them.
The this keyword
The this
keyword refers to the current instance of the class. Here, the parameter name and the name of the class’s field are the same. Hence to avoid ambiguity, the class’s field is prefixed with the this
keyword.
Accessing Attributes and Functions
A class’s attributes and functions can be accessed through the object. Use the “.
” dot notation (called as the period) to access the data members of a class.
//accessing an attribute obj.field_name //accessing a function obj.function_name()
Cascade notation
- The cascade notation (
..
) in Dart allows you to make a sequence of operations on the same object (including function calls and field access). - This notation helps keep Dart code compact and removes the need to create temporary variables to store data.
Encapsulation (Access modifiers)
- In Java, we can use public, protected, and private keywords to control the access scope for a property or method. However, Dart doesn’t provide that
kind of keywords. Instead, you can use_
(underscore) at the start of the name to make a data member of a class becomes private. - In Dart, the privacy is at library level rather than class level. It means other classes and functions in the same library still have the access. So, a data member is either public (if not preceded by
_
) or private (if preceded by_
)
Getters and Setters
- Getters and Setters, also called as accessors and mutators, allow the program to initialize and retrieve the values of class fields respectively. Getters or accessors are defined using the get keyword. Setters or mutators are defined using the set keyword.
- A default getter/setter is associated with every class. However, the default ones can be overridden by explicitly defining a setter/ getter. A getter has no parameters and returns a value, and the setter has one parameter and does not return a value.
Class Inheritance
- Dart supports the concept of Inheritance which is the ability of a program to create new classes from an existing class. The class that is extended to create newer classes is called the parent class/super class. The newly created classes are called the child/sub classes.
- A class inherits from another class using the
extends
keyword. Child classes inherit all properties and methods except constructors from the parent class.
Types of Inheritance
- Inheritance can be of the following three types:
- Single – Every class can at the most extend from one parent class.
- Multiple – A class can inherit from multiple classes. Dart doesn’t support multiple inheritance.
Multi-level – A class can inherit from another child class.
Class Inheritance and Method Overriding
- Method Overriding is a mechanism by which the child class redefines a method in its parent class.
super
keyword
- The
super
keyword is used to refer to the immediate parent of a class. - The
super
keyword can be used to refer to the super class version of a variable, property, or method.
super and constructors
Every subclass in Dart automatically tries to call the default constructor of the superclass. If there isn’t one, you must call the superclass constructor
manually in the initializer list.
Abstract class
- The
abstract
keyword defines a class that cannot be directly instantiated: only its derived classes can. An abstract class can define one (or more)
constructors as usual. - Usually abstract classes contain abstract methods which can be defined putting a semicolon (
;
) instead of the body. You cannot define an abstract
method in a class that’s not been marked with the abstract modifier. - If your class contains at least one method with no body, then it must be abstract and the children must provide an implementation.
Interfaces
- In contrast to other programming languages, Dart does not have an interface keyword and you have to use classes to create interfaces. Your class can
implement more than a single interface. - The keyword is
implements
and, differently from a regular subclass, here you must override every method defined by the class/interface. - In Dart when you use the term interface you are referring to a class that is going to be used by others along with implements because it only provides method signatures. The concept is the same you can find in Java, Delphi or C# with the only difference that Dart doesn’t have a dedicated keyword.
- While extends can be used with only one class, implements works with one or more classes, which you should treat as interfaces (methods with no body).
extends vs implements
- When you use
class B extends A {}
you are NOT forced to override every method of class A. Inheritance takes place and you can override as many methods as you want. This is the typical OOP inheritance that can be used when you want to add some missing features in a subclass. - When you use
class B implements A {}
you must override every method of class A. Inheritance does NOT take place because methods just provide an API, a “skeleton” that the subclass must concretize. - Interfaces are useful when you don’t want to provide an implementation of the functions but just the API. It’s like if the interface was wall socket and the class was the plug that adapts to the holes. While multiple inheritance is not allowed, you can extends a class and implements more than one.
Mixins
- a mixin is simply a class with no constructor that can be “attached” to other classes to reuse the code without inheritance
- mixins like a “copy/paste” tool to reuse methods
override operators
- Operator overloading gives the possibility to customize the usage of operators in your classes.
- Arithmetic operators like
+
,-
,*
, or/
. - Relational operators such as
>=
,<=
,>
or<
. - Equality operators like
!=
and==
callable classes
There is a special call()
method which is very closely related to an operator overload because it allows classes to be called like if they were functions with
the ()
operator.