퇴근5분전

쉽다면 쉽고.. 어렵다면 어려운 패턴이었음.  아직도 가끔은 헷갈리는데...

예제로 본것들중 기억에 남는것은 기자가 각 방송국을 들락 날락 거린다는 예제였던것 같다.

콤보짓 없이 비지터를 살짝쿵.. 비스므리 해보려 했더니... 좀..골때린게 나왔다. 의미상 별거 없어보이긴 하는데..
어쨌거나 저쨌거나..


방문자(Visitor)는 자기가 방문하게될 요소(Ac)에 자기를 등록하도록 Acceptor(방문자 v); 가 요구되고 이를 인터페이스로 구현된다. 
 
이 인터페이스를 통해 방문자의 .Visit( 요소 )를 호출하면서 구조(자료리스트)를 순회 하게 된다. 

단순하게 생각하자!! 

방문자는   방문하게될 대상에 자기가 들어갈 곳을(Acceptor) 요구하고 이를 통해 자기가 들어가서

방문(Visit())을 하게 되며  대상요소에 대한 처리는 Visit() 내에서 처리한다!!..

소스를 보자.. 말로는 역시 풀어내는것은 아직 표현부족으로 한계....

추가:  방문자의 문제 처리를 바꾸고자 한다면

간단히 짝수 출력라인 주석을 하면 홀수만 보이게된다... 일이 구분된다는 것이지.


  public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            Ac a1 = new Ac("a1");  // <== 각 요소들...
            Ac a2 = new Ac("a2");
            Ac a3 = new Ac("a3");
            Ac a4 = new Ac("a4");
            Ac a5 = new Ac("a5");
            Ac a6 = new Ac("a6");
            Ac a7 = new Ac("a7");
            Ac a8 = new Ac("a8");
            Ac a9 = new Ac("a9");
            Ac a10 = new Ac("a10");

            a1._ac = a10; <-- 하위 요소들 추가!!
            a10._ac = a4;
            a5._ac = a7;

            List<Ac> ls = new List<Ac>();  // <-- 비지터가 방문하게될 리스트...
            ls.Add(a1);
            ls.Add(a2);
            ls.Add(a3);
            ls.Add(a5);
            ls.Add(a6);
            ls.Add(a8);
            ls.Add(a9);
          
            Visitor v = new Visitor();
            foreach( Ac item in ls )
            v.Visit(item);  // <--- 각각 방문하게 된다.

            this.textBox1.Text = v.ToString();  // <-- 방문결과...


        }
    }


    public interface IVisitor
    {
        void Visit(Ac ac);
    }

    public interface IAcc
    {
        void Acceptor( IVisitor   v);
    }

 

    public class Ac : IAcc  // <-- 방문하게 될 대상 객체이다.
    {
        static int InstanceCount = 0;
        static void Count() { InstanceCount++; }

        int _i = 0;

        public Ac _ac = null; 
        // <-- 하위 요소가 존재시... 방문자가 순회 하게 될.. 요소로 판정하기 위해... ( 콤포짓 패턴... )

        public int I
        {
            get { return _i; }
        }

        string _name = "";
        public Ac(string __name)
        {
            Count();
            _i = InstanceCount;
            _name = __name;
        }

        #region IAcc 멤버
        public void Acceptor(IVisitor v)
        {
            v.Visit(this); // 비지터에 AC자신에 대한 처리를 맡긴다.
        }
        #endregion

        public override string ToString()
        {
            return _name;
        }
    }


    public class Visitor : IVisitor  //<-- 방문자...
    {
        StringBuilder sb = new StringBuilder();

        public void Clear()
        {
            sb.Remove(0, sb.Length);
        }

        #region IVisitor 멤버

        public void Visit(Ac ac)  //<-- 방문될 요소를 받는다.
        {
            if( ac.I % 2  == 0 )
            {
                 sb.AppendLine(" "+ac.ToString()+"(짝수)");
                 if (ac._ac == null) sb.AppendLine();
            }
            else
            {
                sb.AppendLine(" " + ac.ToString() + "(홀수)");
                if (ac._ac == null) sb.AppendLine();
            }
           
            if (ac._ac != null)
            {
                ac._ac.Acceptor(this); 
               //<-- 하위 요소가 존재시 방문등록을 한다.
                  이로써 방문자는 다시 하위 요소에 자기가 등록되면서 visit가 재귀형태로 호출된다.

            }
        }

        #endregion

        public override string ToString()
        {
            return sb.ToString();
        }
    }