명령 객체를 올바른 수신자와 어떻게 연결합니까?


9

프로젝트에서 실행 취소 및 다시 실행을 구현 하기 위해 명령 패턴 을 사용하려고했습니다.

public abstract class Command
{
    protected Form Receiver { set; get; }
    protected HtmlElement Element { set; get; }
    abstract public void ReDo();
    abstract public void UnDo();
    public Command(Form receiver)
    {
        this.Receiver = receiver;
    }
}
class AddElementCmd : Command
{        
    public AddElementCmd(HtmlElement elem, Form receiver)
        : base(receiver)
    {
        Element = elem;
    }
    public override void ReDo()
    {
        ((FormEdit)Receiver).AddElement(Element,false);
    }
    public override void UnDo()
    {
        ((FormEdit)Receiver).DelElement(Element, false);
    }
}
class DelElementCmd : Command
{
    public DelElementCmd(HtmlElement elem, Form receiver)
        : base(receiver)
    {
        Element = elem;
    }
    public override void ReDo()
    {
        ((FormEdit)Receiver).DelElement(Element, false);
    }
    public override void UnDo()
    {
        ((FormEdit)Receiver).AddElement(Element, false);
    }
}

AddElement명령 구현 FormEdit.

public void AddElement(HtmlElement elem, bool isNew = true)
{
    IHTMLElement2 dom = elem.DomElement as IHTMLElement2;
    if (isNew)
    {
        Command cmd = new AddElementCmd(elem, this);
        Undo.Push(cmd);
        Redo.Clear();
    }    
    // some codes here....
    if (showAlltoolStripButton.Checked)
    {
        dom.runtimeStyle.visibility = "hidden";
    }
    else if (showSelectionToolStripButton.Checked)
    {
        dom.runtimeStyle.visibility = "visible";
    }
 }
...

UndoRedo스택은에 저장되어있는 FormMain클래스와 편집 형태로 전달됩니다.

public Stack<Command> Undo = new Stack<Command>();
public Stack<Command> Redo = new Stack<Command>();

....
FormEdit editor = new FormEdit ();
editor.Browser = webBrowser1;
editor.addedElements = addedElements;
editor.restoreElements = restoreElements;
editor.Undo = Undo;
editor.Redo = Redo;

새로운 FormEdit사용자가 다시 실행 또는 실행 취소 버튼을 클릭하면의 해당 기능 FormEdit이 실행되지만이 명령 수신기를 확인하면 명령이 처음 생성되어 이제 폐기되었을 수 있습니다. 프로그램에서 오류가 발생할 것으로 예상되지만 Command개체가 이전 형식에 대한 참조를 저장하는 것으로 보이며 이로 인해 오작동이 발생합니다.

따라서 명령 자체와 수명이 동일한 기본 양식 또는 webBrowser 컨트롤과 같은 명령에 대한 일관된 수신자를 찾아야한다고 생각합니다. 그러나 명령과 관련된 일부 컨트롤에 액세스해야합니다.

Command객체 의 수신자로서 명령 기능을 구현하기에 가장 좋은 곳은 어디 입니까? 또는 스택에서 튀어 나온 명령에 새 양식을 연결하는 다른 방법.


이 결정이 당신에게 있다고 생각합니다. 응용 프로그램의 사양이나 기능 요구 사항을 모르기 때문에 도와 드릴 수 없습니다.
Euphoric

8
커맨드 객체는 직렬화 가능한 데이터 만 포함해야한다고 생각합니다. 즉, 다른 객체에 대한 참조는 네트워크를 통해 직렬화 된 양식을 전송하거나 나중에 파일로 저장하거나 다른 수신기에서 재생하는 것을 포함하기 때문에 일반적으로 사용됩니다. 예를 들어 변경 사항이 실시간으로 화면에 표시됩니다. 즉, Receiver에서 각 명령 메서드로 전달하거나 Receiver에 자체적으로 전달할 수있는 Receiver executeCommand () / undoCommand () 메서드를 제공하거나 코드 대신 메서드 이름 / 인수 만 포함 된 명령 개체를 사용할 수 있습니다. .
Ixrec


@Ixrec 조언 해 주셔서 감사합니다. 그러면 Receiver각 명령 객체 를 설정할 수 있어야합니다 .
Ahmad

대신 메멘토 패턴을 사용해보십시오.
P. Roe

답변:


1

명령 패턴이 적용되어야 모델 , 아닌 UI. 당신의 경우에, 그것을 만드십시오

protected HtmlDocument Receiver { set; get; }
protected HtmlElement Element { set; get; }

UI를 업데이트하려면 Observer 패턴을 사용하여 열려있는 모든 양식과 해당 컨트롤이 기본 모델의 변경 사항에 반응 할 수 있도록합니다.

Command 는 문서 변경 만 처리 할 수 있고 UI 의 옵저버 는 변경된 내용에 관계없이 컨트롤을 업데이트 하기 만하면되기 때문에 코드가 더 명확 해지고 분리 됩니다.

양식이 닫히면 자신을 옵저버로 등록 취소하고 참조를 유지하지 않습니다.

문서를 변경 한 후 새 양식을 열면 원래 변경시 작성되지 않았더라도 실행 취소 후 알림 이 표시됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.