2017-12-15 8 views
1

일련의 로거를 작성하고 있습니다. 하나는 콘솔에, 하나는 stdout에, 하나는 독점적 인 파일 formart에 씁니다. 언제든지 이러한 로거 중 하나를 구현하고 자체적으로 작업 할 수 있기를 바랍니다.독립적으로 구현할 수있는 데코레이터가있는 데코레이터 패턴

로거를 서로 쌓기 위해 데코레이터 패턴을 사용하려고했지만, 데코레이터가 추가 책임을 스스로 지니고 있지 않다는 것을 알고 있습니다.

내 질문 : 1) 책임은 스스로 할 수있게 받아 들일 수 있습니까? 2) 데코레이터 패턴은 여전히 ​​올바른 경로입니까, 아니면 내가 묘사 한 문제에 더 잘 맞는 패턴이 있습니까?

+0

'장식가는 추가 책임을 스스로 지키려는 의도가 아닙니까?'라는 것이 무엇을 의미합니까?장식자는 항상 느슨하게 결합되어야합니다. 그렇지 않으면 코드의 다른 영역에 적용 할 수 있다는 이점을 잃게됩니다. – timothyclifford

+0

내가 읽고 있던 예에서, 데코레이터는 본질적으로 책임을 추가하고 독립적으로 존재할 수는 없다는 것이 설명되었습니다. 나는 그 가정에서 틀렸다는 것을 알게되어 기쁩니다. – Jason

답변

1

다른 언어를 선호한다면 pseudo C#을 사용했습니다. 알고 싶습니다.

이렇게하려면 먼저 로깅 인터페이스를 만드십시오. 로깅을 수행하는 모든 객체는 다음을 준수합니다.

public interface Logger 
{ 
    void Log(string message); 
} 

다음으로 로깅 기능을 래핑 할 데코레이터 클래스가 필요합니다. 사람들이 직접 인스턴스화하는 것을 원하지 않는다면 추상적 일 수도 있습니다.

public class LoggerDecorator : Logger 
{ 
    Logger logger; 

    public LoggerDecorator(Logger logger) 
    { 
    this.logger = logger; 
    } 

    public override void Log(string message) 
    { 
    logger.log(message); 
    } 
} 

그것은 독립 로거 만들 수있다 : : 그것은 로거 객체 및 프록시이 모든 로그 메시지를 받아

:

public class StdoutLogger : Logger 
{ 
    public override void Log(string message) 
    { 
    // Log message to stdout 
    } 
} 

또는 로거는 단순히 포장 "스택"으로 이러한 당신의 decorator를 사용하여

public class FileAndStdoutLogger : LoggerDecorator 
{ 
    public FileAndStdoutLogger(Logger logger) 
    { 
     super(logger); 
    } 

    public void log(String message) 
    { 
     logger.log(msg); 

     // Log to file 
    } 
} 

그런 다음 사용자가 만들 수있는 독립형 또는 장식 로거 :

var stdoutLogger = new StdoutLogger(); 
stdoutLogger.log("This will log only to stdout"); 

// Will output "This will log only to stdout" to stdout 

var fileAndStdoutLogger = new FileAndStdoutLogger(new StdoutLogger()); 
fileAndStdoutLogger.log("This will log to file & stdout"); 

// Will output "This will log to file & stdout" to file and stdout 

추가 사례가 필요한 경우 알려 주시기 바랍니다.

+0

저는 C++을 사용하고 있습니다. 그러나이 경로는 내가 추락 한 경로입니다. 로거 중 하나는 독립적으로 살 수 있습니다. 로거를 쌓아 두지 않았다면 데코 레이팅 된 로거 중 하나에 대해 평가할 수있는 nullptr 또는 아무 것도 수행하지 않는 빈 로거가 들어 있습니다. – Jason

+0

그러면 나는 네가 올바른 길을 가고 있다고 말할 것이다. 그런데 데코레이션 된 로거가 왜 null 참조를 포함한다고 생각합니까? – timothyclifford

+0

나는 '기본'로거가 반드시 필요하지 않기 때문에. 로거는 순서에 관계없이 추가 할 수 있기 때문에 모두 다른 로거 인스턴스를 주입 할 수 있어야합니다. – Jason

1

나는 이것이 좋은 아이디어라고 생각하지 않습니다 서로

위에 에 로거를 스택 데코레이터 패턴을 사용하도록했다. 장식 패턴은 method call intercepcion 또는 AOP과 같이 작동해야합니다.

즉, 함수 본문을 실행하기 전이나 후에 일부 코드를 실행한다는 의미입니다. 중첩됩니다. 나는 내 로거를 둥지에 넣지 않을 것이다. 로거를 다른 로거에 의존하게하고 싶지 않습니다.

좋은 전략은 일반 로거를 만들고 리스너를 추가하는 것입니다. 모든 청취자는 로그 된 데이터를 쓰는 자체 전략을 가지고 있습니다. .NET 환경에서 Trace and Debug과 같습니다. 그런 다음 일반 로거가 추가 된 수신자 목록을 살펴보고 각각에 log(message)으로 전화하십시오.

그런 다음 데코레이터 패턴을 적용하여 로깅 및 보안과 같은 교차로 관련 문제에 대한 장식 서비스를 작성하십시오.

Public Interface IMyService{ 
    int someAction(); 
} 

Public Class MyService:IMyService{ 
    int someAction(){//impl goes here} 
} 

Public Class SecureMyService:IMyService{ 
    SecureMyService(IMyService innerService){ 
     inner = innerService; 
    } 
    int someAction(){ 
     if (!HasRights()) {throw authorizationException}; 
     return inner.someAction(); 
    } 
} 

Public Class LoggedMyService:IMyService{ 
    SecureMyService(IMyService innerService){ 
     inner = innerService; 
    } 
    int someAction(){ 
     logger.log("invoking some Action"); 
     return inner.someAction(); 
    } 
} 

//resolve decorated service. A DI container does wonderful things for decorator pattern ;) 
IMyService GetService(){ 
    myService = new MyService(); 
    mySecuredService = new SecureMyService(myService); 
    myLoggedAndSecuredService = new LoggedMyService(mySecuredService); 
    return myLoggedAndSecuredService; 
}