반응형
enum class를 이용한 runtime polymorphism
#include <cstdio>
#include <stdexcept>
struct FileLogger {
void log_transfer(long from, long to, double amount) {
--snip--
printf("[file] %ld,%ld,%f\n", from, to, amount);
}
};
struct ConsoleLogger {
void log_transfer(long from, long to, double amount) {
printf("[cons] %ld -> %ld: %f\n", from, to, amount);
}
};
enum class LoggerType {
Console,
File
};
struct Bank {
Bank() : type { LoggerType::Console } { }
void set_logger(LoggerType new_type) {
type = new_type;
}
void make_transfer(long from, long to, double amount) {
--snip--
switch(type) {
case LoggerType::Console: {
consoleLogger.log_transfer(from, to, amount);
break;
} case LoggerType::File: {
fileLogger.log_transfer(from, to, amount);
break;
} default: {
throw std::logic_error("Unknown Logger type encountered.");
} }
}
private:
LoggerType type;
ConsoleLogger consoleLogger;
FileLogger fileLogger;
};
int main() {
Bank bank;
bank.make_transfer(1000, 2000, 49.95);
bank.make_transfer(2000, 4000, 20.00);
bank.set_logger(LoggerType::File);
bank.make_transfer(3000, 2000, 75.00);
}
--------------------------------------------------------------------------
[cons] 1000 -> 2000: 49.950000
[cons] 2000 -> 4000: 20.000000
[file] 3000,2000,75.000000
implementation-inheritance를 이용한 runtime polymorphism. 이는 anti-pattern.
#include <cstdio>
struct Logger {
virtual ~Logger() = default;
virtual void log_transfer(long from, long to, double amount) = 0;
};
struct ConsoleLogger : Logger {
void log_transfer(long from, long to, double amount) override {
printf("%ld -> %ld: %f\n", from, to, amount);
}
};
아래는 constructor injection
#include <cstdio>
struct Logger {
virtual ~Logger() = default;
virtual void log_transfer(long from, long to, double amount) = 0;
};
struct ConsoleLogger : Logger {
void log_transfer(long from, long to, double amount) override {
printf("[cons] %ld -> %ld: %f\n", from, to, amount);
}
};
struct FileLogger : Logger {
void log_transfer(long from, long to, double amount) override {
printf("[file] %ld, %ld, %f\n", from ,to, amount);
}
};
struct Bank {
Bank(Logger& logger) : logger{ logger } { }
void make_transfer(long from, long to, double amount) {
logger.log_transfer(from, to, amount);
}
private:
Logger& logger;
};
int main() {
ConsoleLogger logger;
Bank bank{ logger };
bank.make_transfer(1000, 2000, 49.95);
bank.make_transfer(2000, 4000, 20.00);
}
아래는 property injection.
pointer는 reference와 달리 reseat될 수 있으므로, 여기서는 pointer를 사용
#include <cstdio>
struct Logger {
virtual ~Logger() = default;
virtual void log_transfer(long from, long to, double amount) = 0;
};
struct ConsoleLogger : Logger {
void log_transfer(long from, long to, double amount) override {
printf("[cons] %ld -> %ld: %f\n", from, to, amount);
}
};
struct FileLogger : Logger {
void log_transfer(long from, long to, double amount) override {
printf("[file] %ld, %ld, %f\n", from ,to, amount);
}
};
struct Bank {
void set_logger(Logger* new_logger) {
logger = new_logger;
}
void make_transfer(long from, long to, double amount) {
if (logger) logger->log_transfer(from, to, amount);
}
private:
Logger* logger{};
};
int main() {
ConsoleLogger console_logger;
FileLogger file_logger;
Bank bank;
bank.set_logger(&console_logger);
bank.make_transfer(1000, 2000, 49.95);
bank.set_logger(&file_logger);
bank.make_transfer(2000, 4000, 20.00);
}
property injection을 사용하는 경우 nullptr인지 검사할 필요가 있다.
#include <cstdio>
struct Logger {
--snip--
};
struct Bank {
Bank(Logger* logger) : logger{ logger }{} ➊
void set_logger(Logger* new_logger) { ➋
logger = new_logger;
}
void make_transfer(long from, long to, double amount) {
if (logger) logger->log_transfer(from, to, amount);
}
private:
Logger* logger;
};
반응형
댓글