์ฑ ์ ์ฐ์ ํจํด์ ๋ฌด์์ผ๊น?
์ํค์ ์ค๋ฆฐ ์์
@FunctionalInterface
public interface Logger {
public enum LogLevel {
INFO, DEBUG, WARNING, ERROR, FUNCTIONAL_MESSAGE, FUNCTIONAL_ERROR;
public static LogLevel[] all() {
return values();
}
}
abstract void message(String msg, LogLevel severity);
default Logger appendNext(Logger nextLogger) {
return (msg, severity) -> {
message(msg, severity);
nextLogger.message(msg, severity);
};
}
static Logger writeLogger(LogLevel[] levels, Consumer<String> stringConsumer) {
EnumSet<LogLevel> set = EnumSet.copyOf(Arrays.asList(levels));
return (msg, severity) -> {
if (set.contains(severity)) {
stringConsumer.accept(msg);
}
};
}
static Logger consoleLogger(LogLevel... levels) {
return writeLogger(levels, msg -> System.err.println("Writing to console: " + msg));
}
static Logger emailLogger(LogLevel... levels) {
return writeLogger(levels, msg -> System.err.println("Sending via email: " + msg));
}
static Logger fileLogger(LogLevel... levels) {
return writeLogger(levels, msg -> System.err.println("Writing to Log File: " + msg));
}
}
class Runner {
public static void main(String[] args) {
// Build an immutable chain of responsibility
Logger logger = consoleLogger(LogLevel.all())
.appendNext(emailLogger(LogLevel.FUNCTIONAL_MESSAGE, LogLevel.FUNCTIONAL_ERROR))
.appendNext(fileLogger(LogLevel.WARNING, LogLevel.ERROR));
// Handled by consoleLogger since the console has a LogLevel of all
logger.message("Entering function ProcessOrder().", LogLevel.DEBUG);
logger.message("Order record retrieved.", LogLevel.INFO);
// Handled by consoleLogger and emailLogger since emailLogger implements Functional_Error & Functional_Message
logger.message("Unable to Process Order ORD1 Dated D1 For Customer C1.", LogLevel.FUNCTIONAL_ERROR);
logger.message("Order Dispatched.", LogLevel.FUNCTIONAL_MESSAGE);
// Handled by consoleLogger and fileLogger since fileLogger implements Warning & Error
logger.message("Customer Address details missing in Branch DataBase.", LogLevel.WARNING);
logger.message("Customer Address details missing in Organization DataBase.", LogLevel.ERROR);
}
}
- ์ด๊ฑด ์ข ์ด๋ ค์ฐ๋ ์ ๋ฆฌํด์ ๋ณด์.
Logger Class
public abstract class Logger {
private EnumSet<LogLevel> logLevels;
private Logger next;
public Logger(LogLevel[] levels) {
this.logLevels = EnumSet.copyOf(Arrays.asList(levels));
}
public Logger setNext(Logger next) {
this.next = next;
return this.next;
}
- ์ถ์ ํด๋์ค๋ก ์ ์ธํ์ฌ ๊ณตํต๋ ๋์์ ์ง์ ํจ
logLevel
์ด๋ผ๋ enum set์ผ๋ก ๊ฐ๋ค์ ์งํฉ์ผ๋ก ๋ค๊ณ ์๊ณnext
๋ก ๋๋ค์์ ๋ก๊ฑฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.- ์์ฑ์์์
levels
๋ฅผ ๋ฐ๋๋ฐ, ์ด๋ ํด๋น ๋ก๊ทธ์์ ์ฒ๋ฆฌํ ๋ ๋ฒจ์ ์ ํด์ค๋ค.- ์ฒ๋ฆฌํ ๋ฉ์์ง๋ค์ ํ์ ์ ์ ํด์ค
setNext
๋ฅผ ๋ณด๋ Fluent Interface์ ๋น์ทํ๊ฒ ์๊ฒผ๋ค.- ๊ทผ๋ฐ ๋ฌธ์ ๋ ์๊ธฐ ์์ ์ ๋ฐํํ๋๊ฒ ์๋๊ณ
next
๋ฅผ ๋ฐํํ๋ค.- ์?
- fluent์์ ํ๋จ๊ณ ๋ ๋์๊ฐ๋ค?
- ํด๋ผ์ด์ธํธ ์ชฝ์์๋ ์๊ธฐ๋ฅผ ๋ฐํํ๊ฒ ์ง ํ๊ณ ์๊ฐํ์ง๋ง ๊ทธ๊ฒ ์๋ ๊ผด
- ์ข์ ๋์์ธ์ธ ๊ฒ ๊ฐ์ง๋ ์์
public final void message(String msg, LogLevel severity) {
if (logLevels.contains(severity)) {
log(msg);
}
if (this.next != null) {
this.next.message(msg, severity);
}
}
protected abstract void log(String msg);
}
message
ํจ์๋final
์ด๋ ์์ ๋ถ๊ฐ๋ค.- ๋ฉ์์งํ๊ณ ๋ก๊ทธ ๋ ๋ฒจ ๋ณด๋ด์ ์ฐ๋ ํจ์
- ๋ด๋ถ์ ์ผ๋ก ๋ก๊ฑฐ๊ฐ ์ฒ๋ฆฌ๊ฐ๋ฅํ ๋ ๋ฒจ์ธ์ง ํ์ธํ๊ณ ์ฐ์ด์ค
- ๊ทธ๋ฆฌ๊ณ ๋ค์ ๋ก๊ฑฐ์ ์ ๋ฌํด์ ๋๊ฐ์ด ์ฐ์ด๋ฌ๋ผ๊ณ ์์ฒญ
log
ํจ์๋ ์์๋ฐ๋ ํด๋์ค์์ ๊ตฌํ
ConsoleLogger Class
public class ConsoleLogger extends Logger {
public ConsoleLogger(LogLevel[] levels) {
super(levels);
}
@Override
protected void log(String msg) {
System.err.println("Writing to console: " + msg);
}
}
EmailLogger Class
public class EmailLogger extends Logger {
public EmailLogger(LogLevel[] levels) {
super(levels);
}
@Override
protected void log(String msg) {
System.err.println("Sending via email: " + msg);
}
}
FileLogger Class
public class FileLogger extends Logger {
public FileLogger(LogLevel[] levels) {
super(levels);
}
@Override
protected void log(String msg) {
System.err.println("Writing to file: " + msg);
}
}
enum LogLevel
public enum LogLevel {
INFO,
DEBUG,
WARNING,
ERROR,
FUNCTIONAL_MESSAGE,
FUNCTIONAL_ERROR;
public static LogLevel[] all() {
return values();
}
}
์ค์ ๋ก ์ฌ์ฉํด๋ณด๊ธฐ
Logger logger = new ConsoleLogger(LogLevel.all());
logger
.setNext(new EmailLogger(new LogLevel[]{LogLevel.FUNCTIONAL_MESSAGE, LogLevel.FUNCTIONAL_ERROR}))
.setNext(new FileLogger(new LogLevel[]{LogLevel.WARNING, LogLevel.ERROR}));
// ConsoleLogger์์ ์ฒ๋ฆฌ -> ๋ชจ๋ ๋ก๊ทธ๋ ๋ฒจ ์ฒ๋ฆฌ ๊ฐ๋ฅ
logger.message("Entering function ProcessOrder().", LogLevel.DEBUG);
logger.message("Order record retrieved.", LogLevel.INFO);
// ConsoleLogger, EmailLogger์์ ์ฒ๋ฆฌ ๊ฐ๋ฅ
logger.message("Unable to Process Order ORD1 Dated D1 For Customer C1.", LogLevel.FUNCTIONAL_ERROR);
logger.message("Order Dispatched.", LogLevel.FUNCTIONAL_MESSAGE);
next
๋ก ๋ฉ์์ง๋ฅผ ํธ์ถํ๊ฒ ํด์ ์ฐ์์ ์ผ๋ก ๋ค์ ์น๊ตฌ๋ฅผ ํธ์ถํ ์ ์๊ฒ ๋๋ค.
์ฌ๋ฐ๋ฅธ ์ฑ ์ ์ฐ์ ํจํด ์์
public final class LogManager {
private static LogManager instance;
private ArrayList<Logger> loggers = new ArrayList<Logger>();
public static LogManager getInstance() {
if (instance == null) {
instance = new LogManager();
}
return instance;
}
public void addHandler(Logger logger) {
this.loggers.add(logger);
}
public void message(String msg, LogLevel severity) {
for (Logger logger : this.loggers) {
logger.message(msg, severity);
}
}
}
- ์ ๊ตณ์ด next ํธ์ถํด์ค?
- ์ด๊ฑธ ๋ค ๊ด๋ฆฌํ๋ ๊ฐ์ฒด ํ๋๋ง ์์ผ๋ฉด ๋๋๋ฐ?
public abstract class Logger {
private EnumSet<LogLevel> logLevels;
public Logger(LogLevel[] levels) {
this.logLevels = EnumSet.copyOf(Arrays.asList(levels));
}
public final void message(String msg, LogLevel severity) {
if (logLevels.contains(severity)) {
log(msg);
}
}
protected abstracy void log(String msg);
}
- next๊ฐ ์๋ค.
- ๋๋ ๊ทธ๋ฅ ๋ก๊ทธํ๋ ์ฐ๊ณ ๋!
LogManager logManager = LogManager.getInstance();
logManager.addHandler(new ConsoleLogger(LogLevel.all()));
logManager.addHandler(new EmailLogger(new LogLevel[]{LogLevel.FUNCTIONAL_MESSAGE, LogLevel.FUINCTIONAL_ERROR}));
logManager.message("Entering function ProcessOrder().", LogLevel.DEBUG);
- ์ด๊ฒ ํจ์ฌ ๊ฐ๋จ..
- ๊ตณ์ด โ์ฑ ์ ์ฐ์ ํจํดโ ์ด๋ผ๋ ๊ฒ์ ์ค๋ช ํ๊ธฐ ์ํด ์์ ์๋ฅผ ๊ฐ๋ค๋๊ฒ ์๋ชป
- ๋์์ธ ํจํด ์๋ชป ๋ฐฐ์ฐ๋ฉด ์ํํ๋ค์ ๋จ์ ์ธ ์
- โ์ฐ์โ๋ ํ์ธํจ. ๊ทผ๋ฐ โ์ฑ ์โ์ ์ด๋?
์ฌ๋ฐ๋ฅธ ์ฑ ์ ์ฐ์ ํจํด
- ์ด๋ค ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ์ฌ๋ฌ ๊ฐ์ฒด๊ฐ ์์
- ์ด ๊ฐ์ฒด๋ค์ ์ฐจ๋ก๋๋ก ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ๊ธฐํ๋ฅผ ๋ฐ์
- ๋ง์ฝ ๊ทธ ์ค ํ ๊ฐ์ฒด๊ฐ ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ๋ฉด ๊ทธ๊ฒ์ ๋ํ ์ฑ
์์ ์ง
- ์ฆ ๋ค์ ๊ฐ์ฒด๋ ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ ๊ธฐํ๋ฅผ ๋ฐ์ง ๋ชปํจ
- ๊ทธ๋์ โ์ฑ ์โ ์ฐ์ ํจํด์
- iOS์์๋ Responder chain์ด ๊ทธ์๋ผ ํ ์ ์๊ฒ ๋ค.
์ํคํผ๋์๋ฅผ ์ ๋๋ก ๋ฐ๊พธ๋ฉด..
public final void message(String msg, LogLevel severity) {
if (logLevels.contains(severity)) {
log(msg);
}
if (this.next != null) {
this.next.message(msg, severity);
}
}
public final void message(String msg, LogLevel severity) {
if (logLevels.contains(severity)) {
log(msg);
} else if (this.next != null) {
this.next.message(msg, severity);
}
}
- ๋ด๊ฐ ์ฒ๋ฆฌ๋ชปํ๋ฉด ๋ค์์ผ๋ก ๋๊ฒจ
- ๋ด๊ฐ ํ ์ ์์ผ๋ฉด ๋ด๊ฐ ํ๊ณ ๋!