← → or space · progress saves for Continue on the roadmap
Goal
Depend on a Logger abstraction; swap sinks without changing callers.
Step 1 - Interface
abstract class Logger {
void info(String message);
void error(String message);
}Step 2 - Console implementation
class ConsoleLogger implements Logger {
@override
void info(String message) => print('[INFO] $message');
@override
void error(String message) => print('[ERROR] $message');
}Step 3 - Fake file logger (no real I/O)
class FileLogger implements Logger {
final String path;
final List<String> lines = [];
FileLogger(this.path);
@override
void info(String message) {
lines.add('$path [INFO] $message');
}
@override
void error(String message) {
lines.add('$path [ERROR] $message');
}
}Step 4 - Service uses Logger
class Greeter {
final Logger log;
Greeter(this.log);
void hello(String name) {
log.info('hello $name');
}
}
void main() {
Greeter(ConsoleLogger()).hello('Asha');
FileLogger f = FileLogger('/tmp/app.log');
Greeter(f).hello('Rafi');
print(f.lines.join('\n'));
}Practice tasks
- Add
void warn(String message)toLoggerand update both implementations. - Inject
Loggerinto a second service (for exampleUserServicethat logs sign-in). - Add
MultiLogger(List<Logger> sinks)that forwards each method to every sink.