// WHAT: A mixin is a set of fields and methods that can be reused by multiple classes. // WHY: To allow 'SmartSpeaker' to have connection logic without forcing 'SmartLight' to have it. mixin Connectable { // WHAT: A boolean instance variable initialized to false. // WHY: To track whether a specific device is currently linked to a network or bluetooth. bool isConnected = false; // WHAT: A function using arrow syntax (=>) to negate the current boolean. // WHY: Provides a standardized, reusable way to flip the connection state for any class using this mixin. void toggleConnection() => isConnected = !isConnected; } // WHAT: An abstract class acting as a base template. // WHY: It defines the shared "DNA" of all devices but prevents anyone from creating a generic "SmartDevice". abstract class SmartDevice { // WHAT: A final String that can only be set once. // WHY: Ensures the device's unique identifier remains immutable (unchangeable) after creation. final String id; // WHAT: A private String (indicated by the underscore). // WHY: Encapsulation; it hides raw data so we can control how it's accessed or formatted via getters/setters. String _name; // WHAT: Private boolean state for power. // WHY: To keep the "ON/OFF" state internal to the object, requiring a method call to change it. bool _powerStatus = false; // WHAT: Private boolean for automation. // WHY: To track if the device should handle its own power timing without user intervention. bool _auto_on_off = false; // WHAT: A static constant String. // WHY: This belongs to the class itself (the brand), not the individual instances. static const String brand = "GeminiHome"; // 1. Standard Constructor // WHAT: A generative constructor using 'user_provided' naming. // WHY: Maps the external input (user_provided_id) to the internal final field (id). SmartDevice({ required String user_provided_id, required String user_provided_name }) : id = user_provided_id, _name = user_provided_name; // 2. Named Constructor: Office // WHAT: A specialized constructor for a specific use-case. // WHY: It streamlines creation by hardcoding the name and auto-mode for office settings. SmartDevice.office({ required String user_provided_id }) : id = user_provided_id, _name = "Office Desk Lamp", _auto_on_off = true; // 3. Named Constructor: Eco // WHAT: A specialized constructor for power saving. // WHY: It ensures the device starts in an "OFF" state with "Auto" mode enabled for efficiency. SmartDevice.eco({ required String user_provided_id }) : id = user_provided_id, _name = "Eco Saver Unit", _powerStatus = false, _auto_on_off = true; // 4. Factory Constructor // WHAT: A factory that decides which subclass to create. // WHY: It allows the "SmartDevice" class to return a "SmartLight" or "SmartSpeaker" based on a String input. factory SmartDevice.create({ required String user_provided_type, required String user_provided_id, required String user_provided_name, }) { // WHAT: Logic to check the 'type' string. // WHY: To determine which concrete implementation is needed for the user's request. if (user_provided_type == 'light') { return SmartLight(user_provided_id: user_provided_id, user_provided_name: user_provided_name); } return SmartSpeaker(user_provided_id: user_provided_id, user_provided_name: user_provided_name); } // WHAT: A public Getter for the private name. // WHY: Allows other parts of the app to read the name without being able to overwrite it directly. String get name => _name; // WHAT: A public Setter with a .trim() method. // WHY: Cleans the input data (removing spaces) before saving it to the private '_name' field. set name(String user_provided_new_name) => _name = user_provided_new_name.trim(); // WHAT: An abstract method signature (no curly braces). // WHY: It forces every subclass to define what "performing an action" actually means for that specific device. void performAction(); // WHAT: A concrete method shared by all subclasses. // WHY: To avoid code duplication; every smart device uses the same logic to toggle power. void togglePower() { // WHAT: Boolean inversion. // WHY: Changes 'true' to 'false' or vice versa to simulate a power switch. _powerStatus = !_powerStatus; print('$_name is now ${_powerStatus ? "ON" : "OFF"} (Auto-mode: $_auto_on_off)'); } } // WHAT: A concrete implementation of a SmartDevice. // WHY: To add specific properties (like brightness) that only a light would have. class SmartLight extends SmartDevice { // WHAT: An integer specific to this class. // WHY: To track how bright the light is; initialized to 100 by default. int brightness = 100; // WHAT: Standard constructor passing data to the super class. // WHY: To ensure a custom light gets its ID and Name correctly initialized in the base class. SmartLight({ required String user_provided_id, required String user_provided_name }) : super(user_provided_id: user_provided_id, user_provided_name: user_provided_name); // WHAT: Named constructor with an extra assignment in the initializer list. // WHY: It combines the "Office" defaults from the parent with a specific "50%" brightness for this subclass. SmartLight.office({ required String user_provided_id }) : brightness = 50, // Sets the brightness specifically for office use. super.office(user_provided_id: user_provided_id); // Calls the parent's office logic. // WHAT: Named constructor for Eco mode. // WHY: Redirects to the eco settings in the base class (e.g., auto-off enabled). SmartLight.eco({ required String user_provided_id }) : brightness = 20, // WHY: Maybe Eco mode should be even dimmer to save more power! super.eco(user_provided_id: user_provided_id); @override // WHAT: Implementation of the abstract method. // WHY: To display the specific state (brightness) of this light. void performAction() { print('[$_name] Brightness: $brightness%'); } } // WHAT: A concrete implementation using inheritance (SmartDevice) and a mixin (Connectable). // WHY: To create a device that has a name/id AND the ability to connect/disconnect. class SmartSpeaker extends SmartDevice with Connectable { // WHAT: A double (0.0 to 1.0) for audio level. // WHY: Specific data needed only for audio-based devices. double volume; // WHAT: Constructor with an assertion check. // WHY: The 'assert' stops the program during debugging if the volume is out of bounds (0.0 - 1.0). SmartSpeaker({ required String user_provided_id, required String user_provided_name, this.volume = 0.5, }) : assert(volume >= 0 && volume <= 1.0), super(user_provided_id: user_provided_id, user_provided_name: user_provided_name); @override // WHAT: Concrete implementation of the abstract method. // WHY: Defines that for a Speaker, "performing an action" includes checking the connection status. void performAction() { print('[$_name] Volume: ${(volume * 100).toInt()}%. Connected: $isConnected'); } } // --- EXECUTION --- void main() { // WHAT: Instantiating a Light using the Office preset. // WHY: To demonstrate how named constructors simplify creating specific device configurations. final workLamp = SmartLight.office(user_provided_id: 'OFFICE_01'); // WHAT: Instantiating a Light using the Eco preset. // WHY: Shows the reuse of the super.eco logic. final ecoLight = SmartLight.eco(user_provided_id: 'ECO_99'); // WHAT: Standard instantiation of a SmartLight. // WHY: Demonstrates creating an object with custom labels. final customLight = SmartLight( user_provided_id: 'CUST_01', user_provided_name: 'My Custom Light' ); // WHAT: Using the factory constructor. // WHY: Shows how the 'SmartDevice' base class can act as a single entry point to create different types of objects. final speaker = SmartDevice.create( user_provided_type: 'speaker', user_provided_id: 'SPK_01', user_provided_name: 'Living Room Bass' ); // WHAT: Printing and calling methods. // WHY: To verify that all constructors and methods are working as expected. print('--- Testing Presets ---'); workLamp.performAction(); workLamp.togglePower(); print(''); ecoLight.performAction(); ecoLight.togglePower(); print(''); speaker.performAction(); }