Object-Oriented Programming: Classes and Constructors
Dart is a pure object-oriented language where everything is an object. Classes are blueprints for creating objects.
Basic Class Definition
dart
class Person {
String name;
int age;
// Constructor
Person(this.name, this.age);
// Method
void introduce() {
print('Hi, I\'m $name and I\'m $age years old.');
}
}
void main() {
Person person = Person('Alice', 25);
person.introduce(); // Hi, I'm Alice and I'm 25 years old.
}Constructors
Default Constructor
dart
class Point {
double x;
double y;
Point(this.x, this.y);
}
void main() {
Point p = Point(10, 20);
}Named Constructors
dart
class Point {
double x, y;
Point(this.x, this.y);
// Named constructor
Point.origin()
: x = 0,
y = 0;
Point.fromJson(Map<String, double> json)
: x = json['x']!,
y = json['y']!;
}
void main() {
Point p1 = Point(5, 10);
Point p2 = Point.origin();
Point p3 = Point.fromJson({'x': 3.0, 'y': 4.0});
}Initializer List
dart
class Rectangle {
double width, height, area;
Rectangle(this.width, this.height)
: area = width * height;
Rectangle.square(double size)
: width = size,
height = size,
area = size * size;
}Redirecting Constructors
dart
class Point {
double x, y;
Point(this.x, this.y);
// Redirect to main constructor
Point.alongXAxis(double x) : this(x, 0);
Point.alongYAxis(double y) : this(0, y);
}Const Constructors
dart
class ImmutablePoint {
final double x, y;
const ImmutablePoint(this.x, this.y);
}
void main() {
const p1 = ImmutablePoint(1, 2);
const p2 = ImmutablePoint(1, 2);
print(identical(p1, p2)); // true (same instance)
}Factory Constructors
dart
class Logger {
static final Map<String, Logger> _cache = {};
final String name;
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
Logger._internal(this.name);
void log(String message) {
print('[$name] $message');
}
}
void main() {
var logger1 = Logger('UI');
var logger2 = Logger('UI');
print(identical(logger1, logger2)); // true (same instance)
}Properties
Getters and Setters
dart
class Rectangle {
double width, height;
Rectangle(this.width, this.height);
// Getter
double get area => width * height;
// Setter
set area(double value) {
width = value / height;
}
double get perimeter => 2 * (width + height);
}
void main() {
var rect = Rectangle(10, 5);
print(rect.area); // 50.0
rect.area = 100;
print(rect.width); // 20.0
}Private Members
Use underscore _ prefix for private members:
dart
class BankAccount {
String _accountNumber;
double _balance;
BankAccount(this._accountNumber, this._balance);
double get balance => _balance;
void deposit(double amount) {
if (amount > 0) {
_balance += amount;
}
}
bool withdraw(double amount) {
if (amount > 0 && amount <= _balance) {
_balance -= amount;
return true;
}
return false;
}
}Static Members
dart
class MathUtils {
static const double pi = 3.14159;
static int callCount = 0;
static double circleArea(double radius) {
callCount++;
return pi * radius * radius;
}
}
void main() {
print(MathUtils.pi); // 3.14159
print(MathUtils.circleArea(5)); // 78.53975
print(MathUtils.callCount); // 1
}Instance Methods
dart
class Calculator {
int add(int a, int b) => a + b;
int subtract(int a, int b) => a - b;
int multiply(int a, int b) => a * b;
double divide(int a, int b) => a / b;
}Operator Overloading
dart
class Vector {
final double x, y;
Vector(this.x, this.y);
Vector operator +(Vector other) {
return Vector(x + other.x, y + other.y);
}
Vector operator -(Vector other) {
return Vector(x - other.x, y - other.y);
}
Vector operator *(double scalar) {
return Vector(x * scalar, y * scalar);
}
@override
bool operator ==(Object other) {
return other is Vector && x == other.x && y == other.y;
}
@override
int get hashCode => Object.hash(x, y);
@override
String toString() => 'Vector($x, $y)';
}Callable Classes
dart
class Multiplier {
final int factor;
Multiplier(this.factor);
int call(int value) => value * factor;
}
void main() {
var triple = Multiplier(3);
print(triple(5)); // 15
print(triple.call(5)); // 15 (same)
}Complete Example
dart
class BankAccount {
final String _accountNumber;
String _holderName;
double _balance;
static int _totalAccounts = 0;
// Constructor
BankAccount(this._accountNumber, this._holderName, [double initialBalance = 0])
: _balance = initialBalance {
_totalAccounts++;
}
// Named constructor
BankAccount.savings(String accountNumber, String holderName)
: this(accountNumber, holderName, 100);
// Getters
String get accountNumber => _accountNumber;
String get holderName => _holderName;
double get balance => _balance;
// Setter
set holderName(String name) {
if (name.isNotEmpty) {
_holderName = name;
}
}
// Static getter
static int get totalAccounts => _totalAccounts;
// Methods
void deposit(double amount) {
if (amount > 0) {
_balance += amount;
print('Deposited: \$$amount. New balance: \$$_balance');
}
}
bool withdraw(double amount) {
if (amount > 0 && amount <= _balance) {
_balance -= amount;
print('Withdrawn: \$$amount. New balance: \$$_balance');
return true;
}
print('Insufficient funds');
return false;
}
void transfer(BankAccount recipient, double amount) {
if (withdraw(amount)) {
recipient.deposit(amount);
print('Transferred \$$amount to ${recipient.accountNumber}');
}
}
@override
String toString() {
return 'Account: $_accountNumber, Holder: $_holderName, Balance: \$$_balance';
}
}
void main() {
var account1 = BankAccount('ACC001', 'Alice', 1000);
var account2 = BankAccount.savings('ACC002', 'Bob');
print(account1);
print(account2);
account1.deposit(500);
account1.withdraw(200);
account1.transfer(account2, 300);
print('\nFinal balances:');
print(account1);
print(account2);
print('\nTotal accounts: ${BankAccount.totalAccounts}');
}