Files
flutter_projects/dart_ex_1/ex_2.dart
2026-03-27 21:04:40 +07:00

187 lines
6.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
mixin Connectable {
bool isConnected = false;
void toggleConnection() => isConnected = !isConnected;
}
abstract class SmartDevice {
final String id;
String _name;
bool _powerStatus = false;
bool _auto_on_off = false;
static const String brand = "GeminiHome";
// 1. Standard Constructor with named parameters
SmartDevice({required this.id, required String name}) : _name = name;
// 2. Named Constructor: Preset for Office use
SmartDevice.office({required this.id})
: _name = "Office Desk Lamp",
_auto_on_off = true;
// 3. Named Constructor: Preset for Eco mode
SmartDevice.eco({required this.id})
: _name = "Eco Saver Unit",
_powerStatus = false,
_auto_on_off = true;
// 4. Factory Constructor using named parameters
factory SmartDevice.create({
required String type,
required String id,
required String name,
}) {
if (type == 'light') return SmartLight(id: id, name: name);
return SmartSpeaker(id: id, name: name);
}
// Specialized factory for the Office preset
factory SmartDevice.createOffice({required String id}) {
return SmartLight.office(id: id);
}
String get name => _name;
set name(String value) => _name = value.trim();
void performAction();
void togglePower() {
_powerStatus = !_powerStatus;
print('$_name is now ${_powerStatus ? "ON" : "OFF"} (Auto-mode: $_auto_on_off)');
}
}
class SmartLight extends SmartDevice {
int brightness = 100;
// Using 'super' syntax with named parameters
SmartLight({required super.id, required super.name});
// Redirecting to parent named constructors
SmartLight.office({required String id}) : super.office(id: id);
SmartLight.eco({required String id}) : super.eco(id: id);
@override
void performAction() {
print('[$_name] Brightness: $brightness%');
}
}
class SmartSpeaker extends SmartDevice with Connectable {
double volume;
SmartSpeaker({
required String id,
required String name,
this.volume = 0.5,
}) : assert(volume >= 0 && volume <= 1.0),
super(id: id, name: name);
@override
void performAction() {
print('[$_name] Volume: ${(volume * 100).toInt()}%. Connected: $isConnected');
}
}
void main() {
// --- USAGE ---
// 1. Using the 'Office' preset with named ID
final workLamp = SmartLight.office(id: 'OFFICE_01');
// 2. Using the 'Eco' preset with named ID
final ecoLight = SmartLight.eco(id: 'ECO_99');
// 3. Standard creation using clear labels for ID and Name
final customLight = SmartLight(id: 'CUST_01', name: 'My Custom Light');
// 4. Using the factory with named parameters
final speaker = SmartDevice.create(
type: 'speaker',
id: 'SPK_01',
name: 'Living Room Bass'
);
print('--- Testing Presets ---');
workLamp.performAction();
workLamp.togglePower();
print('');
ecoLight.performAction();
ecoLight.togglePower();
print('');
speaker.performAction();
}
// You're absolutely right. Understanding *why* we use these features is more important than just knowing the syntax. Lets 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—its always a specific light, speaker, or thermostat.
// * **Use Case:** In a Large App, you might have a `List<SmartDevice> 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 its 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?