From 9e868dcb17ee1ac4a54439887c7935d62588144f Mon Sep 17 00:00:00 2001 From: narawat lamaiin Date: Fri, 27 Mar 2026 18:34:00 +0700 Subject: [PATCH] update --- dart_ex_1/ex_2.dart | 160 ++++++++++++++++++++++++++++++++++++++++++++ dart_ex_1/main.dart | 11 +++ 2 files changed, 171 insertions(+) create mode 100644 dart_ex_1/ex_2.dart diff --git a/dart_ex_1/ex_2.dart b/dart_ex_1/ex_2.dart new file mode 100644 index 0000000..bc352fb --- /dev/null +++ b/dart_ex_1/ex_2.dart @@ -0,0 +1,160 @@ +// A Mixin: Adds specific behavior without being a parent class +mixin Connectable { + bool isConnected = false; + void toggleConnection() => isConnected = !isConnected; +} + +abstract class SmartDevice { + final String id; // Final: Set once + String _name; // Private field (starts with _) + bool _powerStatus = false; + + static const String brand = "GeminiHome"; // Static: Shared by all instances + + // 1. Generative Constructor + SmartDevice(this.id, this._name); + + // 2. Named Constructor + SmartDevice.temp(this.id) : _name = "Unknown Device"; + + // 3. Factory Constructor: Decides which subclass to return + factory SmartDevice.create(String type, String id, String name) { + if (type == 'light') return SmartLight(id, name); + return SmartSpeaker(id, name); + } + + // Getter and Setter + String get name => _name; + set name(String value) => _name = value.trim(); + + // Abstract method: Must be implemented by children + void performAction(); + + // Regular method + void togglePower() { + _powerStatus = !_powerStatus; + print('$_name is now ${_powerStatus ? "ON" : "OFF"}'); + } +} + + + +class SmartLight extends SmartDevice { + int brightness = 100; + + // Uses 'super' to pass data to the parent constructor + SmartLight(super.id, super.name); + + @override + void performAction() { + print('Adjusting brightness to $brightness%'); + } +} + + + + +// 'with Connectable' adds the toggleConnection() method to this class +class SmartSpeaker extends SmartDevice with Connectable { + double volume; + + // 4. Initializer List: Sets volume before the constructor body runs + SmartSpeaker(String id, String name, {this.volume = 0.5}) + : assert(volume >= 0 && volume <= 1.0), + super(id, name); + + // 5. Redirecting Constructor: Forwards to the main constructor + SmartSpeaker.loud(String id, String name) : this(id, name, volume: 1.0); + + @override + void performAction() { + print('Playing music at ${volume * 100}% volume. WiFi: $isConnected'); + } +} + + + + +void main() { + // Using the Factory + final myLight = SmartDevice.create('light', 'L1', 'Living Room Lamp'); + + // Using the Redirecting Constructor + final partySpeaker = SmartSpeaker.loud('S1', 'Bass Blaster'); + + myLight.togglePower(); // Parent method + partySpeaker.toggleConnection(); // Mixin method + partySpeaker.performAction(); // Overridden method +} + + + + + +// You're absolutely right. Understanding *why* we use these features is more important than just knowing the syntax. Let’s break down the rationale and real-world use cases for the structure I built. + +// --- + +// ## 1. The Abstract Class (`SmartDevice`) +// **Rationale:** You want to define a "contract." Every smart device must have an ID, a name, and an action, but a "generic" smart device doesn't exist in reality—it’s always a specific light, speaker, or thermostat. + +// * **Use Case:** In a Large App, you might have a `List devices`. You can loop through this list and call `.togglePower()` on every item without knowing if it's a light or a speaker. This is the heart of **Polymorphism**. + +// --- + +// ## 2. Factory Constructors (`SmartDevice.create`) +// **Rationale:** Normal constructors always create a new instance of the exact class they belong to. A `factory` constructor is more flexible: it can return a subclass or even a cached instance. + +// * **Use Case:** **API Parsing.** When you get JSON data from a server, you don't know the device type until you read the data. A factory constructor can look at the "type" field in the JSON and decide to return a `SmartLight` object or a `SmartSpeaker` object automatically. + +// --- + +// ## 3. Mixins (`with Connectable`) +// **Rationale:** Dart doesn't allow a class to have two parents (Multiple Inheritance) because it gets messy. Mixins allow you to "plug in" shared behavior across unrelated classes. + + + +// * **Use Case:** Imagine you have a `SmartSpeaker` (a device) and a `PhoneApp` (not a device). Both need "WiFi Connection" logic. Instead of copying the code twice, you create a `Connectable` mixin and apply it to both. + +// --- + +// ## 4. Getters and Setters +// **Rationale:** This is about **Encapsulation**. You should never let outside code touch your internal variables (`_name`) directly. By using a setter, you can "sanitize" the data. + +// * **Use Case:** Validation. If a user tries to set a device name to a string full of empty spaces, your setter `set name(value) => _name = value.trim();` automatically cleans it up before it’s saved to your database. + +// --- + +// ## 5. Redirecting Constructors (`SmartSpeaker.loud`) +// **Rationale:** To avoid "Boilerplate" (repetitive code). If you have a common configuration for a class, you don't want to rewrite the initialization logic. + +// * **Use Case:** **Presets.** In a UI, you might have a "Default" button and a "Pro" button. Instead of manually setting 10 different parameters each time, you create a named constructor like `Button.primary()` that redirects to the main constructor with all the "Pro" settings pre-filled. + +// --- + +// ## 6. Static Members (`static const brand`) +// **Rationale:** Memory efficiency. If you have 1,000 smart lights, you don't need the string "GeminiHome" stored in memory 1,000 times. + +// * **Use Case:** **Configuration & Constants.** Use `static` for things that are "Universal truth" for the class, such as a maximum volume limit or a shared API version number. + +// Would you like me to show you how to handle **Interfaces** in Dart, which is the final piece of the OO puzzle? + + + + + + + + + + + + + + + + + + + + diff --git a/dart_ex_1/main.dart b/dart_ex_1/main.dart index 64a84f4..815a958 100644 --- a/dart_ex_1/main.dart +++ b/dart_ex_1/main.dart @@ -83,3 +83,14 @@ void main() { // ------------------------------------------------------------------ + + + + + + + + + + +