Object-oriented programming (OOP) is a programming paradigm centered on the concept of "objects," which can contain data in the form of fields, sometimes referred to as attributes or properties, and code in the form of procedures, also called methods. As an object-oriented programming language, Dart embraces this paradigm and provides a rich set of features to implement OOP concepts effectively.
The core of object-oriented programming involves creating classes, which are blueprints for objects. In Dart, a class can be defined using the class keyword. For example, a class student might represent the data and functionality associated with a student. This class would have instance variables to hold data, such as a student's name and ID, and methods to perform operations on this data.
1class Student { 2 String name; 3 int id; 4 5 void study() { 6 print('Studying'); 7 } 8} 9
Name and id are instance variables in the above example, and study is a method. The class student can be instantiated to create many objects, each representing a different student with unique data.
Dart strengthens its position as an object-oriented programming language by incorporating all the fundamental OOP principles, such as encapsulation, inheritance, and polymorphism. Dart objects are instances of classes and center interaction within a Dart application.
In Dart, instance variables can have default values and be final or non-final. Non-final instance variables can be changed after an object is created, while final ones cannot. Dart also provides implicit getter and setter methods, for instance, variables, allowing for controlled access and modification of these variables.
1class Student { 2 String name; 3 int _id; // Private to the library due to the underscore 4 5 int get id => _id; 6 set id(int value) => _id = value; 7} 8
In the above example, _id is a private instance variable with an implicit getter method and an implicit setter method, allowing other parts of the code to access and modify the ID in a controlled manner.
In Dart, a class serves as a blueprint for creating objects. It encapsulates data and functions that operate on the data. Instance variables represent the data, and methods represent the functions. We use the class keyword to define a class, followed by the class name and a pair of curly braces {}.
1class Point { 2 int x; 3 int y; 4 5 void moveTo(int newX, int newY) { 6 x = newX; 7 y = newY; 8 } 9} 10
In the above example, class Point has two instance variables, x and y, and a method named moveTo. The instance variables hold the data for the class, while the method provides behavior.
A constructor is a special class function called when a new class instance is created. In Dart, a constructor has the same name as the class. It can have constructor arguments to initialize instance variables with values when an object is created.
1class Point { 2 int x; 3 int y; 4 5 Point(this.x, this.y); 6 7 void moveTo(int newX, int newY) { 8 x = newX; 9 y = newY; 10 } 11} 12
In the above example, the class Point has a constructor that takes two parameters, x and y, and sets the instance variables to the values passed in when a new instance of Point is created. The this keyword refers to the current instance.
Dart also supports named constructors, which allow a class to define multiple constructors with different names.
1class Point { 2 int x; 3 int y; 4 5 Point(this.x, this.y); 6 Point.origin() { 7 x = 0; 8 y = 0; 9 } 10} 11
In the above example, class Point has a named constructor Point.origin which initializes the instance variables to a default origin point (0,0).
Constructors can also have optional parameters, which allow you to omit arguments when creating a new instance.
1class Point { 2 int x; 3 int y; 4 5 Point([this.x = 0, this.y = 0]); 6} 7
Here, the constructor for class Point has optional parameters with default values of 0, so you can create a new instance of Point without providing any arguments, and it will default to the origin.
Once a class is defined, we can create objects by instantiating the class. Each object created from a class is an instance of that class. In Dart, we use the new keyword to instantiate a class, although it's optional and often omitted.
1void main() { 2 Point p = new Point(2, 3); 3 print(p.x); // Accessing the instance variable 'x' 4 p.moveTo(5, 6); // Calling the instance method 'moveTo' 5} 6
In the above example, within the void main function, we create a new instance of class Point and assign it to the variable p. We then access the instance variables and call the instance method moveTo to change the object's state.
The lifecycle of an instance in Dart begins when it is created using a constructor. The instance remains alive if there is a reference to it in the code. Once no more references exist to the instance, Dart's garbage collector will eventually reclaim the memory, effectively ending the instance's lifecycle.
1void main() { 2 var p1 = Point(2, 3); 3 var p2 = p1; // p2 is now a reference to the same instance as p1 4 p1 = null; // The original reference to the instance is removed, but p2 still refers to it 5} 6
In the void main function of the above example, p1 is initially a reference to a new instance of class Point. When we assign p1 to p2, both variables refer to the same instance. Setting p1 to null removes one reference, but the instance continues because p2 still refers to it.
Instance methods are functions defined within a class and used to perform operations on instances of that class. These methods can access and modify instance variables, providing behavior to dart objects.
1class Student { 2 String name; 3 int age; 4 5 void celebrateBirthday() { 6 age++; 7 print('$name is now $age years old.'); 8 } 9} 10
In the above example, the class student has an instance method called celebrateBirthday, which increments the age instance variable and prints a message. To call this method, you would create an instance of class student and then use the dot notation.
1void main() { 2 Student student = Student() 3 ..name = 'Alice' 4 ..age = 20; 5 6 student.celebrateBirthday(); // Alice is now 21 years old. 7} 8
In the void main function, we create a new student and then call the celebrateBirthday method. The cascade operator (..) is used to access multiple instance variables or methods on the same object.
Static methods belong to the class itself rather than to class instances. They are often used as utility functions relevant to the class.
1class MathHelper { 2 static int add(int a, int b) { 3 return a + b; 4 } 5} 6
In the above example, add is a static method of the class MathHelper. It can be called without creating an instance of the class.
1void main() { 2 int sum = MathHelper.add(10, 5); 3 print(sum); // 15 4} 5
In the void main function, we call the static method add directly on the class name MathHelper without needing to instantiate it.
Static methods are useful when an approach does not need to access any instance variables or instance methods of a class. They can be called directly using the class name, which can conveniently organize helper functions and other utility codes.
In exploring object-oriented programming in Dart, we've covered the fundamental concepts that make Dart a powerful and flexible language for OOP. From defining classes and their properties to understanding constructors and creating instances, we've seen how dart objects are brought to life and interacted with. We've also delved into the behavior of these objects through instance methods and the utility of static methods at the class level.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.