Classes and Objects: Classes are blueprints for creating objects.
Encapsulation: Restrict access to properties and methods using private variables.
Inheritance: Classes can inherit methods and properties from other classes using extends.
Polymorphism: Achieved by method overriding and interfaces.
Abstraction: Abstract classes hide implementation details.
Interfaces and Multiple Inheritance: Implement multiple classes to achieve interface-like behavior.
class className { // Creating Class named className
String field = ''; // Creating Field inside the class
void fun() // Creating method/Function inside class
{
print("Welcome to $field");
}
}
void main()
{
className fun = new className(); // Creating Instance of class
// Calling field name field and assigning value
fun.field = 'Sandeep'; // to it using object of the class className
fun.fun(); // Calling function name fun using object of the class className
}
Object-Oriented Programming (OOP) is a programming paradigm based on the concept of objects. In Dart, OOP is a key feature that enables developers to create modular, reusable, and maintainable code. The four main principles of OOP—encapsulation, inheritance, polymorphism, and abstraction—are all supported in Dart.
Here’s an explanation of how OOP concepts are implemented in Dart:
Class: A blueprint for creating objects. It defines properties (variables) and methods (functions) that the objects will have.
Object: An instance of a class.
class Car {
// Properties
String brand;
String model;
int year;
// Constructor
Car(this.brand, this.model, this.year);
// Method
void displayInfo() {
print("Car: $brand $model ($year)");
}
}
void main() {
// Creating an object of the Car class
Car car1 = Car('Toyota', 'Corolla', 2020);
car1.displayInfo(); // Car: Toyota Corolla (2020)
}
Encapsulation is the bundling of data and methods that operate on the data into a single unit (class). It also restricts direct access to some of the class’s components.
In Dart, you can use private variables (with _ prefix) to protect data from being accessed directly from outside the class.
class BankAccount {
double _balance; // Private property
// Constructor
BankAccount(this._balance);
// Method to get balance
double get balance => _balance;
// Method to deposit money
void deposit(double amount) {
if (amount > 0) {
_balance += amount;
}
}
}
void main() {
var account = BankAccount(1000);
account.deposit(500);
print(account.balance); // 1500
}
Inheritance allows a class to inherit properties and methods from another class.
Dart uses the extends keyword for inheritance.
class Animal {
void speak() {
print("Animal makes a sound");
}
}
class Dog extends Animal {
// Overriding the speak method
@override
void speak() {
print("Dog barks");
}
}
void main() {
Dog dog = Dog();
dog.speak(); // Dog barks
}
Polymorphism allows a class to have different implementations of the same method.
You can override a method in a subclass or use the method from a parent class.
class Shape {
void draw() {
print("Drawing shape");
}
}
class Circle extends Shape {
@override
void draw() {
print("Drawing circle");
}
}
class Square extends Shape {
@override
void draw() {
print("Drawing square");
}
}
void main() {
Shape shape1 = Circle();
shape1.draw(); // Drawing circle
Shape shape2 = Square();
shape2.draw(); // Drawing square
}
Abstraction hides the complexity of the system and shows only the essential features.
In Dart, you can use abstract classes to create classes that cannot be instantiated directly but can be extended by other classes.
abstract class Animal {
void speak(); // Abstract method
}
class Dog extends Animal {
@override
void speak() {
print("Dog barks");
}
}
void main() {
// Animal animal = Animal(); // This would cause an error, since Animal is abstract
Dog dog = Dog();
dog.speak(); // Dog barks
}
Dart supports multiple types of constructors, including named constructors and factory constructors.
class Point {
double x, y;
// Default constructor
Point(this.x, this.y);
// Named constructor
Point.origin() : x = 0, y = 0;
}
void main() {
Point p1 = Point(5, 7);
print(p1.x); // 5
print(p1.y); // 7
Point p2 = Point.origin();
print(p2.x); // 0
print(p2.y); // 0
}
Classes and Objects: The fundamental building blocks of OOP in Dart.
Encapsulation: Keeping data safe and restricting access to it.
Inheritance: Reusing code by creating a class hierarchy.
Polymorphism: Having different implementations of methods for different classes.
Abstraction: Hiding complexity and exposing only the necessary features.
A class is a blueprint for creating objects. Objects are instances of classes.
-------------------------------------------------------------------------------
In Dart, classes and objects are fundamental concepts in Object-Oriented Programming (OOP). A class serves as a blueprint for creating objects, and an object is an instance of a class, holding specific data and behaviors.
A class in Dart defines the properties (attributes) and methods (functions) that the objects created from it will have.
Classes encapsulate data and functionality, making it easy to reuse and organize code.
class className { // Creating Class named className
String field = ''; // Creating Field inside the class
void fun() // Creating method/Function inside class
{
print("Welcome to $field");
}
}
void main()
{
className fun = new className(); // Creating Instance of class
// Calling field name field and assigning value
fun.field = 'Sandeep'; // to it using object of the class className
fun.fun(); // Calling function name fun using object of the class className
}
Another Example of a Class in Dart:
class Person // Properties (attributes)
{
String name;
int age;
Person(this.name, this.age); // Constructor
void introduce() // Method (behavior)
{
print("Hello, my name is $name, and I am $age years old.");
}
}
In this example:
Person is a class with two attributes: name and age.
It has a constructor (Person(this.name, this.age)) to initialize these properties when creating a new object.
The introduce method is a behavior that an instance of Person can perform.
An object is an instance of a class. When a class is defined, you can create objects that contain their own copies of the class's properties and can use its methods.
Creating an Object in Dart:
void main()
{
Person person1 = Person("Sandeep", 33); // Creating an object(person1) of the Person class
Person person2 = Person("Pradeep", 30); // Creating an object(person2) of the Person class
// Accessing attributes
print(person1.name); // Output: Sandeep
print(person1.age); // Output: 33
print(person2.name); // Output: Pradeep
print(person2.age); // Output: 30
// Calling a method /Function
person1.introduce(); // Output: Hello, my name is Alice, and I am 30 years old.
person2.introduce();
}
In this example:
person1 is an object of the Person class.
We access its attributes (name and age) and call its method (introduce).
Class: A template that defines attributes and behaviors. You define the structure but do not allocate memory for variables until an object is created.
Object: An instance of a class with specific data and accessible methods.
Constructors
Dart allows different types of constructors:
Default Constructor: Used for initializing default values.
Named Constructors: Helpful for creating different versions of an object.
Example of a Named Constructor:
class Person {
String name;
int age;
Person(this.name, this.age); // Default constructor
Person.anonymous() : name = "Anonymous", age = 0; // Named constructor
}
void main() {
Person person1 = Person("Alice", 30);
Person person2 = Person.anonymous();
print(person1.name); // Output: Alice
print(person2.name); // Output: Anonymous
}
Methods: Define the behavior of the objects. You can create instance methods, which operate on individual objects.
Getters and Setters: Dart provides the ability to define getters and setters for encapsulation and data control.
Example of a Getter and Setter:
class Rectangle {
double _width;
double _height;
Rectangle(this._width, this._height);
double get area => _width * _height; // Getter for area
set width(double value) => _width = value; // Setter to modify width
}
void main() {
Rectangle rect = Rectangle(5.0, 4.0);
print("Area: ${rect.area}"); // Output: Area: 20.0
rect.width = 6.0;
print("New Area: ${rect.area}"); // Output: New Area: 24.0
}
In this example, area is a getter, and width is a setter.
Class: Defines a blueprint with attributes and behaviors.
Object: An instance of a class with specific values.
Constructors: Initialize objects; Dart supports default and named constructors.
Encapsulation: Achieved through private attributes, getters, and setters.
Encapsulation is the concept of restricting access to certain properties and methods by using access modifiers (private, public). In Dart, a member is private to its library if its name starts with an underscore (_).
class BankAccount {
double _balance = 0; // Private variable
void deposit(double amount) // Public method to access the private variable
{
_balance += amount;
}
double get balance => _balance; // Getter to access private variable
}
void main()
{
BankAccount account = BankAccount();
account.deposit(1000);
print("Balance: \$${account.balance}");
}
--------------------------------------------------
In Dart, encapsulation is a core principle of Object-Oriented Programming (OOP), which is about bundling data (attributes) and methods (behaviors) within a class and controlling access to them. Encapsulation helps in keeping the data safe from outside interference and misuse.
In Dart, encapsulation is primarily achieved through:
Private Variables and Methods: Using the _ (underscore) prefix to make variables and methods private to the library or file.
Getters and Setters: Controlling access to private variables using getter and setter methods.
Let’s look at an example of encapsulation with a BankAccount class.
class BankAccount
{
double _balance; // Private attribute (property)
BankAccount(this._balance); // Constructor
double get balance => _balance; // Getter for balance (read-only access)
void deposit(double amount) // Method to deposit money
{
if (amount > 0) {
_balance += amount;
print("Deposited: \$${amount}");
} else {
print("Deposit amount should be positive.");
}
}
void withdraw(double amount) // Method to withdraw money
{
if (amount > 0 && amount <= _balance) {
_balance -= amount;
print("Withdrawn: \$${amount}");
} else {
print("Invalid withdrawal amount.");
}
}
}
Private Attribute: _balance is a private variable (notice the underscore _ before its name) and cannot be accessed directly from outside the BankAccount class.
Getter Method: The balance getter provides read-only access to _balance, so the value can be checked from outside but not modified.
Deposit and Withdraw Methods: These methods provide controlled access to the _balance variable, enforcing rules like preventing negative deposits or withdrawals greater than the balance.
void main()
{
BankAccount account = BankAccount(100.0);
print("Initial balance: \$${account.balance}"); // Accessing balance via the getter
// Using deposit and withdraw methods
account.deposit(50.0); // Deposited: $50.0
account.withdraw(30.0); // Withdrawn: $30.0
account.withdraw(200.0); // Invalid withdrawal amount
print("Current balance: \$${account.balance}");
}
Data Protection: By hiding sensitive data (like _balance), we prevent it from being modified directly.
Controlled Access: Through methods and getters/setters, we can enforce rules and conditions for data access and modification.
Ease of Maintenance: Encapsulation makes the code modular, allowing changes to the internal implementation without affecting external code.
Encapsulation in Dart, just like in other OOP languages, helps in creating robust, secure, and easy-to-maintain code.
Inheritance allows one class to inherit properties and methods from another class using the extends keyword. This promotes code reuse.
class Animal // Parent class
{
void eat() {
print("Animal is eating.");
}
}
class Dog extends Animal // Child class inheriting from Animal
{
void bark() {
print("Dog is barking.");
}
}
void main()
{
Dog dog = Dog();
dog.eat(); // Method from Animal class
dog.bark(); // Method from Dog class
}
---------------------------------------------------
Inheritance is a key principle in Object-Oriented Programming (OOP) that allows a class to inherit properties and methods from another class. In Dart, inheritance enables you to create a new class (child class) based on an existing class (parent class), promoting code reusability and hierarchical relationships between classes.
Superclass (Parent Class): The class from which properties and methods are inherited.
Subclass (Child Class): The class that inherits from the superclass.
In Dart, the extends keyword is used to inherit from a superclass.
Let's create a Vehicle class (the parent class) and a Car class (the child class) that inherits from Vehicle.
class Vehicle // Parent class
{
String brand;
int year;
Vehicle(this.brand, this.year);
void displayInfo() {
print("Brand: $brand, Year: $year");
}
}
class Car extends Vehicle // Child class
{
int doors;
Car(String brand, int year, this.doors) : super(brand, year);
void showCarDetails()
{
displayInfo();
print("Doors: $doors");
}
}
void main()
{
Car myCar = Car("Toyota", 2022, 4);
myCar.showCarDetails();
}
In this example:
The Vehicle class is the parent class with attributes brand and year, a constructor, and a displayInfo method.
The Car class is the child class that extends Vehicle, inheriting its properties and methods.
The Car class has an additional attribute, doors, and a method, showCarDetails, which displays details specific to Car.
When we run the showCarDetails method on myCar, the output will be:
plaintext
Copy code
Brand: Toyota, Year: 2022
Doors: 4
1. Calling the Parent Constructor with super
The super keyword is used to call the parent class's constructor. In the Car constructor, super(brand, year) calls the Vehicle constructor, initializing brand and year.
2. Overriding Methods
The child class can override a method from the parent class to change or extend its behavior. I
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++n Dart, the @override annotation is used to explicitly mark an overridden method.
Example of Method Overriding:
class Vehicle {
String brand;
int year;
Vehicle(this.brand, this.year);
void displayInfo() {
print("Vehicle Brand: $brand, Year: $year");
}
}
class Car extends Vehicle {
int doors;
Car(String brand, int year, this.doors) : super(brand, year);
@override
void displayInfo()
{
super.displayInfo(); // Optionally call parent method
print("This is a car with $doors doors.");
}
}
void main() {
Car myCar = Car("Honda", 2021, 4);
myCar.displayInfo();
}
Output:
Vehicle Brand: Honda, Year: 2021
This is a car with 4 doors.
In this example, displayInfo in the Car class overrides the method in the Vehicle class and adds more specific information. By calling super.displayInfo(), we include the parent class's implementation as part of the overridden method.
3. Using super to Call Parent Methods
Aside from constructors, super can also be used to call methods from the parent class within an overridden method, as shown in the previous example.
Dart supports single inheritance only, meaning each class can inherit from only one parent class (no multiple inheritance). However, you can use mixins to achieve functionality similar to multiple inheritance.
Using Mixins
Mixins allow you to add functionalities to classes without needing a hierarchical relationship. In Dart, you can create a mixin using the mixin keyword and add it to classes using the with keyword.
Example:
mixin Electric {
void chargeBattery() {
print("Battery charging...");
}
}
class Car {
String brand;
Car(this.brand);
void drive() {
print("$brand car is driving.");
}
}
class ElectricCar extends Car with Electric {
ElectricCar(String brand) : super(brand);
}
void main() {
ElectricCar myTesla = ElectricCar("Tesla");
myTesla.drive(); // Output: Tesla car is driving.
myTesla.chargeBattery(); // Output: Battery charging...
}
In this example:
Electric is a mixin that provides the chargeBattery method.
ElectricCar inherits from Car and uses the Electric mixin to add electric-specific functionality.
Inheritance allows a child class to acquire the properties and behaviors of a parent class.
extends is used to establish inheritance.
super is used to call the parent class's constructor and methods.
Method Overriding lets child classes modify or extend the behavior of parent methods.
Mixins (mixin and with) allow you to add reusable functionalities without formal inheritance, providing flexibility for adding multiple behaviors to a class.
Inheritance in Dart allows for code reuse, logical structure, and extensibility.
Polymorphism allows one interface to be used for different data types.
In Dart, polymorphism can be achieved through method overriding and interfaces.
class Animal
{
void sound() {
print("Animal makes a sound.");
}
}
class Dog extends Animal {
@override
void sound() {
print("Dog barks.");
}
}
class Cat extends Animal {
@override
void sound() {
print("Cat meows.");
}
}
void main() {
Animal dog = Dog(); // Polymorphism: Dog treated as Animal
Animal cat = Cat(); // Polymorphism: Cat treated as Animal
dog.sound(); // Dog's version of sound
cat.sound(); // Cat's version of sound
}
--------------------------------------------------------------------------------------------------------------
Polymorphism is an important concept in Object-Oriented Programming (OOP) that allows objects of different classes to be treated as objects of a common superclass. In Dart, polymorphism enables you to call the same method on different objects, and each object can respond differently based on its own implementation.
There are two main types of polymorphism in Dart:
Compile-time polymorphism (method overloading, which is limited in Dart)
Run-time polymorphism (method overriding, which Dart fully supports)
In some languages, compile-time polymorphism (method overloading) allows you to define multiple methods with the same name but different parameters. However, Dart does not support traditional method overloading directly, meaning you can’t define multiple methods with the same name in the same scope.
Instead, Dart achieves similar functionality using optional positional parameters or named parameters in methods.
Example using optional parameters:
class Calculator {
// Single method with optional parameters
int add(int a, [int b = 0, int c = 0]) {
return a + b + c;
}
}
void main() {
Calculator calc = Calculator();
print(calc.add(5)); // Output: 5
print(calc.add(5, 10)); // Output: 15
print(calc.add(5, 10, 15)); // Output: 30
}
In this example, the add method accepts one, two, or three arguments due to optional parameters, effectively achieving compile-time polymorphism.
Run-time polymorphism, or method overriding, is the most common type of polymorphism in Dart. It allows a subclass to provide a specific implementation of a method defined in its superclass. When you call the overridden method on an object of the subclass, Dart dynamically determines which method to execute based on the object’s type at runtime.
To override a method in Dart, you use the @override annotation in the subclass.
Example of Run-time Polymorphism:
// Parent class
class Animal {
void makeSound() {
print("Animal makes a sound");
}
}
// Child class 1
class Dog extends Animal {
@override
void makeSound() {
print("Dog barks");
}
}
// Child class 2
class Cat extends Animal {
@override
void makeSound() {
print("Cat meows");
}
}
void main() {
Animal myDog = Dog();
Animal myCat = Cat();
myDog.makeSound(); // Output: Dog barks
myCat.makeSound(); // Output: Cat meows
}
In this example:
The Animal class has a makeSound method.
Both Dog and Cat classes extend Animal and override the makeSound method.
When makeSound is called on myDog (an instance of Dog), it prints "Dog barks."
When makeSound is called on myCat (an instance of Cat), it prints "Cat meows."
Dart allows you to use interfaces to achieve polymorphism. Any class in Dart implicitly defines an interface, and you can implement multiple interfaces in a single class using the implements keyword. When a class implements an interface, it must provide concrete implementations for all the methods of that interface.
Example of Polymorphism with Interfaces:
// Interface for Printable
class Printable {
void printDetails();
}
// Class 1 implementing Printable
class Book implements Printable {
String title;
Book(this.title);
@override
void printDetails() {
print("Book title: $title");
}
}
// Class 2 implementing Printable
class Newspaper implements Printable {
String name;
Newspaper(this.name);
@override
void printDetails() {
print("Newspaper name: $name");
}
}
void main() {
List<Printable> printItems = [Book("Dart Programming"), Newspaper("The Daily News")];
// Using polymorphism to call printDetails on different types of objects
for (var item in printItems) {
item.printDetails();
}
}
Output:
Book title: Dart Programming
Newspaper name: The Daily News
In this example:
Printable is an interface with the printDetails method.
Both Book and Newspaper classes implement the Printable interface and provide their own printDetails method.
We create a list of Printable items and call printDetails on each item, demonstrating polymorphism by handling objects of different types through a common interface.
Code Reusability: Common methods defined in a superclass can be reused and overridden by subclasses.
Flexibility: You can write code that works with objects of different classes but treats them as objects of a common superclass or interface.
Scalability: Adding new subclasses or implementations requires minimal changes to existing code.
Polymorphism allows methods to be used interchangeably on objects of different types.
Compile-time polymorphism is achieved with optional or named parameters (since Dart does not support true method overloading).
Run-time polymorphism is achieved with method overriding.
Interfaces allow you to define shared behavior across unrelated classes, further supporting polymorphism.
Polymorphism in Dart enables you to create flexible and extensible code by defining methods that can be used with different types of objects while hiding the specifics of each type’s implementation.
Abstraction means hiding the implementation details and exposing only the necessary functionality. In Dart, abstraction can be achieved using abstract classes and interfaces. An abstract class cannot be instantiated, and it can have abstract methods that must be implemented by subclasses.
// Abstract class
abstract class Shape {
// Abstract method
double area();
void display() {
print("This is a shape.");
}
}
// Class extending abstract class
class Circle extends Shape {
double radius;
Circle(this.radius);
// Implementing the abstract method
@override
double area() => 3.14 * radius * radius;
}
void main() {
Circle circle = Circle(5);
circle.display();
print("Area of the circle: ${circle.area()}");
}
---------------------------------------------------------------------------------------------------------------
Abstraction is an essential concept in Object-Oriented Programming (OOP) that focuses on hiding complex details and showing only the necessary features of an object. In Dart, abstraction is achieved through abstract classes and interfaces, allowing you to define a blueprint of a class without implementing its entire functionality.
Abstraction helps in:
Simplifying code by exposing only essential features.
Encouraging code reusability and maintainability.
Enforcing a contract for subclasses to implement certain methods, ensuring a consistent API.
In Dart, an abstract class is a class that cannot be instantiated directly. You define an abstract class by using the abstract keyword. An abstract class can have:
Abstract methods (methods without a body that must be implemented by subclasses).
Concrete methods (methods with a body).
Subclasses of an abstract class must provide concrete implementations for all abstract methods.
Example of an Abstract Class:
// Abstract class
abstract class Shape {
// Abstract method
void draw();
// Concrete method
void printShape() {
print("This is a shape.");
}
}
// Subclass that implements the abstract class
class Circle extends Shape {
@override
void draw() {
print("Drawing a circle.");
}
}
// Another subclass
class Rectangle extends Shape {
@override
void draw() {
print("Drawing a rectangle.");
}
}
void main() {
Shape shape1 = Circle();
Shape shape2 = Rectangle();
shape1.draw(); // Output: Drawing a circle.
shape2.draw(); // Output: Drawing a rectangle.
shape1.printShape(); // Output: This is a shape.
}
In this example:
Shape is an abstract class with an abstract method draw and a concrete method printShape.
The Circle and Rectangle classes extend Shape and implement the draw method, providing specific implementations for each shape.
Since Shape is abstract, you cannot create an instance of Shape directly (Shape shape = Shape(); would cause an error).
Abstract methods are methods without a body, and they must be implemented by the subclasses. In Dart, you do not need to use the abstract keyword on methods inside an abstract class—they are abstract by default if they lack a body.
In Dart, interfaces also enable abstraction. Every class in Dart defines an implicit interface. By using the implements keyword, you can enforce that a class provides concrete implementations for all the methods and properties defined in the interface.
Example of Abstraction with Interfaces:
// Interface class
class Printer {
void printDocument();
}
// Implementing the interface
class InkjetPrinter implements Printer {
@override
void printDocument() {
print("Printing document with Inkjet Printer...");
}
}
class LaserPrinter implements Printer {
@override
void printDocument() {
print("Printing document with Laser Printer...");
}
}
void main() {
Printer inkjet = InkjetPrinter();
Printer laser = LaserPrinter();
inkjet.printDocument(); // Output: Printing document with Inkjet Printer...
laser.printDocument(); // Output: Printing document with Laser Printer...
}
In this example:
Printer serves as an interface with a printDocument method.
InkjetPrinter and LaserPrinter implement Printer and provide their own implementations of printDocument.
You can treat both InkjetPrinter and LaserPrinter as Printer objects, demonstrating polymorphism with abstraction.
Abstract Classes: Used when you want to provide some base functionality along with abstract methods. Subclasses inherit both abstract and concrete methods from the abstract class.
Interfaces: Used when you want to define a contract only, without any implementation. Classes implementing an interface must provide full implementations for all methods.
Consider an example of a payment system where each payment method has its own way of processing payments.
// Abstract class
abstract class PaymentMethod {
void processPayment(double amount); // Abstract method
}
// CreditCard class implementing processPayment
class CreditCard extends PaymentMethod {
@override
void processPayment(double amount) {
print("Processing credit card payment of \$${amount}");
}
}
// PayPal class implementing processPayment
class PayPal extends PaymentMethod {
@override
void processPayment(double amount) {
print("Processing PayPal payment of \$${amount}");
}
}
void main() {
PaymentMethod payment1 = CreditCard();
PaymentMethod payment2 = PayPal();
payment1.processPayment(100.0); // Output: Processing credit card payment of $100.0
payment2.processPayment(75.0); // Output: Processing PayPal payment of $75.0
}
Here:
PaymentMethod is an abstract class with an abstract method processPayment.
CreditCard and PayPal classes extend PaymentMethod and provide specific implementations for processPayment.
Abstraction focuses on hiding the details and showing only essential features to the user.
Abstract classes are used to define abstract methods that subclasses must implement.
Interfaces (implicit in Dart) define a contract that implementing classes must follow.
Polymorphism and Abstraction: Abstract classes and interfaces promote polymorphism, allowing for flexible and scalable code structures.
Abstraction in Dart helps build clean, reusable, and maintainable code, focusing on the "what" rather than the "how."
Dart doesn't have a keyword for interfaces like some other languages. Instead, every class can act as an interface, and a class can implement multiple classes (acting like interfaces).
class Printer {
void printDocument() {
print("Printing document...");
}
}
class Scanner {
void scanDocument() {
print("Scanning document...");
}
}
// Multiple inheritance-like behavior using interfaces
class AllInOnePrinter implements Printer, Scanner {
@override
void printDocument() {
print("All-in-one printer printing...");
}
@override
void scanDocument() {
print("All-in-one printer scanning...");
}
}
void main() {
AllInOnePrinter printer = AllInOnePrinter();
printer.printDocument();
printer.scanDocument();
}