Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn Practical Refactoring Example | Composition and Polymorphism
Dart OOP Essentials

bookPractical Refactoring Example

Refactoring procedural code into object-oriented programming (OOP) is a foundational skill for any Dart developer aiming to build maintainable and scalable applications. By moving from flat, function-based code to structured classes and interfaces, you can better organize logic, make code easier to extend, and reduce the risk of bugs as your project grows.

main.dart

main.dart

copy
12345678910111213141516171819202122232425262728293031
// Procedural approach to managing shapes import 'dart:math'; // Calculate area for a circle double circleArea(double radius) { return pi * radius * radius; } // Calculate area for a rectangle double rectangleArea(double width, double height) { return width * height; } void printShapeArea(String shape, Map<String, double> params) { double area; if (shape == 'circle') { area = circleArea(params['radius']!); print('Circle area: $area'); } else if (shape == 'rectangle') { area = rectangleArea(params['width']!, params['height']!); print('Rectangle area: $area'); } else { print('Unknown shape'); } } void main() { printShapeArea('circle', {'radius': 5}); printShapeArea('rectangle', {'width': 4, 'height': 6}); }

In the procedural version, you manage shapes using separate functions and a control flow that checks shape types with strings. This approach leads to scattered logic, making it difficult to add new shapes or change existing behavior without editing multiple places in the code. The refactored OOP version introduces a Shape abstract class, which defines a common interface for all shapes. Both Circle and Rectangle inherit from Shape, implementing their own area methods. The printShapeArea function now accepts any Shape, supporting polymorphism and making it easy to add new shapes by simply extending the Shape class. This design centralizes logic, improves readability, and reduces the chance of errors when extending functionality.

main.dart

main.dart

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
// main.dart // Refactored OOP with interfaces for extensibility import 'dart:math'; // Interface for drawable objects abstract class Drawable { void draw(); } // Shape interface for polymorphism abstract class Shape { double area(); } // Circle implements both Shape and Drawable class Circle implements Shape, Drawable { final double radius; Circle(this.radius); @override double area() => pi * radius * radius; @override void draw() { print('Drawing a circle with radius $radius'); } } // Rectangle implements both Shape and Drawable class Rectangle implements Shape, Drawable { final double width; final double height; Rectangle(this.width, this.height); @override double area() => width * height; @override void draw() { print('Drawing a rectangle of $width x $height'); } } void printShapeArea(Shape shape) { print('${shape.runtimeType} area: ${shape.area()}'); } void drawShape(Drawable drawable) { drawable.draw(); } void main() { Shape circle = Circle(5); Shape rectangle = Rectangle(4, 6); printShapeArea(circle); printShapeArea(rectangle); drawShape(circle as Drawable); drawShape(rectangle as Drawable); }
question mark

What is a key advantage of refactoring procedural code into object-oriented code?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 3. ChapterΒ 3

Ask AI

expand

Ask AI

ChatGPT

Ask anything or try one of the suggested questions to begin our chat

Suggested prompts:

Can you show an example of the procedural and OOP versions side by side?

What are some best practices for refactoring procedural code to OOP in Dart?

How does using an abstract class improve code maintainability in this context?

bookPractical Refactoring Example

Swipe to show menu

Refactoring procedural code into object-oriented programming (OOP) is a foundational skill for any Dart developer aiming to build maintainable and scalable applications. By moving from flat, function-based code to structured classes and interfaces, you can better organize logic, make code easier to extend, and reduce the risk of bugs as your project grows.

main.dart

main.dart

copy
12345678910111213141516171819202122232425262728293031
// Procedural approach to managing shapes import 'dart:math'; // Calculate area for a circle double circleArea(double radius) { return pi * radius * radius; } // Calculate area for a rectangle double rectangleArea(double width, double height) { return width * height; } void printShapeArea(String shape, Map<String, double> params) { double area; if (shape == 'circle') { area = circleArea(params['radius']!); print('Circle area: $area'); } else if (shape == 'rectangle') { area = rectangleArea(params['width']!, params['height']!); print('Rectangle area: $area'); } else { print('Unknown shape'); } } void main() { printShapeArea('circle', {'radius': 5}); printShapeArea('rectangle', {'width': 4, 'height': 6}); }

In the procedural version, you manage shapes using separate functions and a control flow that checks shape types with strings. This approach leads to scattered logic, making it difficult to add new shapes or change existing behavior without editing multiple places in the code. The refactored OOP version introduces a Shape abstract class, which defines a common interface for all shapes. Both Circle and Rectangle inherit from Shape, implementing their own area methods. The printShapeArea function now accepts any Shape, supporting polymorphism and making it easy to add new shapes by simply extending the Shape class. This design centralizes logic, improves readability, and reduces the chance of errors when extending functionality.

main.dart

main.dart

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
// main.dart // Refactored OOP with interfaces for extensibility import 'dart:math'; // Interface for drawable objects abstract class Drawable { void draw(); } // Shape interface for polymorphism abstract class Shape { double area(); } // Circle implements both Shape and Drawable class Circle implements Shape, Drawable { final double radius; Circle(this.radius); @override double area() => pi * radius * radius; @override void draw() { print('Drawing a circle with radius $radius'); } } // Rectangle implements both Shape and Drawable class Rectangle implements Shape, Drawable { final double width; final double height; Rectangle(this.width, this.height); @override double area() => width * height; @override void draw() { print('Drawing a rectangle of $width x $height'); } } void printShapeArea(Shape shape) { print('${shape.runtimeType} area: ${shape.area()}'); } void drawShape(Drawable drawable) { drawable.draw(); } void main() { Shape circle = Circle(5); Shape rectangle = Rectangle(4, 6); printShapeArea(circle); printShapeArea(rectangle); drawShape(circle as Drawable); drawShape(rectangle as Drawable); }
question mark

What is a key advantage of refactoring procedural code into object-oriented code?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 3. ChapterΒ 3
some-alt