ExtJs > ExtNet 변환 툴!!!
이번 프로젝트에서 ExtJs 디자이너로 화면을 만들어 놓은것을
Ext.Net에 맞춰 변환 하는 프로그램을 만들면서 살짝 이력을 남겨본다.
# 정보수집..
1. 자바스크립 Object 구성으로 만들어진다. composite!
2. 그렇다면 트리 구조로 데이타를 추적할수 있다.
3. 문자열 > Object 변환이 필요하다. json으로 되는지 보자.
4. 각 프로퍼티에 대응하는 object 프로퍼티 맵을 어떻게 구성해야 하는지.. 고민해봐야 한다.
5. 기간! 주어진 시간이 짧기에 [ 변환 소스 만드는 시간 = 손으로 바꿔야 하는 시간 ] 이 쌤쌤이어야 한다.
! 정보수집 된 내용을 기반으로 머리속에서 프로그램이 동작하는 부분들을 미리 이미지화 한다.
# 제작..
쿵짝 쿵짝.. 만드는데 3시간, 테스트 3시간!!
# 결과
OK! 소스 변환까지는 금방 완성이 되었는데... 다른 일들이 껴들어와서 누적시간이 더 걸렸음.
테스트 할때는 실제 변환해서 화면에 뿌려보니 디자이너로 제작한 내용과 다른 부분들이 존재하여
추적하여 디버깅하였음.
리플렉션 + 대리자를 이용! 소스가 엄청 짧고 간단한다.
# Hint!
소스 라인은 833 라인!으로 ExtJs의 필요한 부분들을 최대한 필요한 만큼 수용한 변환 툴 완성!
- 사용된 디자인 패턴 : Visitor [ 역시 타입별로 대응해서 뭔가 처리 하고자 할때 ... 좋음. ]
# 변환기 호출 처리 로직
1.
string // 변환된 문자열
ToConvert (
EXTNETBASE ex, // 변환 대상
int depth, // 현재 깊이
Func<EXTNETBASE, int, string> Fn // 변환기
)
2.
Func<EXTNETBASE, int, string> // 타입에 맞는 변환메서드
GetConvert(
string xType // 타입
)
3.
string // 타입에 맞는 변환 결과
ToContainer(
EXTNETBASE ex, // 변환 대상
int depth // 깊이
)
기본 흐름은 위처럼 변환대상에 대해 시작하면(ToConvert) 해당 타입을 변환 할 수 있는 메서드를 꺼내서(GetConvert)
변환(ToContainer)!
public interface IVisitor
{
string Visit(IAcceptor act);
}
public interface IAcceptor
{
EXTNETBASE GetInstance();
string Acceptor(IVisitor visit);
}
이번에 개발하면서 대리자+ 리플렉션 이용해서 소스를 줄이고 시간을 벌었다.
// extjs 의 문자열들을 object 트리 구조로 변환 시켜줌 ( Json이용 )
EXTNETBASE m = JsonConvert.DeserializeObject<EXTNETBASE>(" extjs design source ");
// 트리구조의 object를 비지터로 모두 순회 하면서 각 타입별로 변환 시킴.
ExtNetConverter vis = new ExtNetConverter();
string s = m.Acceptor(vis);
// Object
public class EXTNETBASE : IAcceptor
{
public Collection<EXTNETBASE> items { get; set; }
public string Id { get; set; }
public string name { get; set; }
public string xtype { get; set; }
. . .
public string Acceptor(IVisitor visit)
{
return visit.Visit(this);
}
public EXTNETBASE GetInstance()
{
return this;
}
}
public class ExtNetConverter : IVisitor
{
public string Visit(IAcceptor act)
{
EXTNETBASE cont = act.GetInstance();
return ToConvert(cont, 0, GetConvert(cont.xtype));
}
// 탭의 깊이만큼 생성 반환!
static Func<int, string> Tab = (depth) => { return new string('\t', depth); };
// 구조의 깊이를 추적할수 있는 대리자.
static Func<EXTNETBASE, string, int, int> CalcMaxDepth = (ext, collectionPropertyName, depth) => {
// todo : 트리구조이므로 깊이를 추적함.
PropertyInfo collectionProperty = ext.GetType().GetProperty(collectionPropertyName, BindingFlags.Public | BindingFlags.Instance);
if (collectionProperty != null)
{
Collection<EXTNETBASE> coll = collectionProperty.GetValue(ext, null) as Collection<EXTNETBASE>;
if (coll != null)
{
int maxChildDepth = 0;
int temp = 0;
foreach (var item in coll)
{
temp += CalcMaxDepth(item, collectionPropertyName, depth);
if (temp > maxChildDepth) temp = maxChildDepth;
}
depth += maxChildDepth;
}
}
return depth;
};
string ToConvert(EXTNETBASE ex, int depth, Func<EXTNETBASE, int, string> Fn) {
// todo : 객체별 변환메서드를 호출하며, 탭으로 서식 유지 시켜 보기 편하게 만듬.
string result = Tab(depth) + (Fn != null ? Fn(ex, depth) : "@*## Convert미지원 " + ex.xtype + " ##*@");
if (ex.items != null && ex.items.Count > 0)
{
result += ".Items(" + Environment.NewLine + string.Join(","+Environment.NewLine, ex.items.Select(s =>
ToConvert(s, depth+1, GetConvert(s.xtype))).ToArray());
int itemDepth = CalcMaxDepth(ex, "items", depth);
result += Environment.NewLine + Environment.NewLine + Tab( itemDepth ) + ")";
}
if (ex.dockedItems != null && ex.dockedItems.Count > 0)
{
result += ".DockedItems(" + Environment.NewLine + string.Join("," + Environment.NewLine, ex.dockedItems.Select(s =>
ToConvert(s, depth+1, GetConvert(s.xtype))).ToArray());
int dockedItemsDepth = CalcMaxDepth(ex, "dockedItems", depth);
result += Environment.NewLine + Environment.NewLine + Tab(dockedItemsDepth) + ")";
}
if (ex.gridcolumns != null && ex.gridcolumns.Count > 0)
{
result += ".ColumnModel(" + Environment.NewLine + string.Join("," + Environment.NewLine, ex.gridcolumns.Select(s =>
ToConvert(s, depth+1, GetConvert(s.xtype))).ToArray());
int columnModelDepth = CalcMaxDepth(ex, "gridcolumns", depth );
result += Environment.NewLine + Environment.NewLine + Tab(columnModelDepth) + ")";
}
return result;
}
Func<EXTNETBASE, int, string> GetConvert(string xType)
{
// todo : 각 타입별 변환 메서드 반환
switch (("" + xType).ToLower())
{
default:
return new Func<EXTNETBASE, int, string>((e, i) => { return @"@*"+xType+"*@"; });
case "container":
return ToContainer;
case "textfield":
return ToTextfield;
case "textareafield":
return ToTextareafield;
... 각 타입별 변환 메서드!
}
}
string ToContainer(EXTNETBASE ex, int depth)
{
string content = "X.Container()";
content += GetCommonConvert(ex);
return content;
}
string GetCommonConvert(EXTNETBASE ex, string opt = "")
{
// todo : 객체들 공통프로퍼티 변환목록을 묶어서 진행.
}
private static string GetPropertyConvert(EXTNETBASE ex, string propertyName, string opt = "")
{
// todo : Js변환 대상 프로퍼티 -> Net 변환
}
// 이후로는
// 20여개의 변환 메서드
// 15개 정도의 프로퍼티 변환처리.
}
'# 1) 프로그래밍' 카테고리의 다른 글
비동기 처리] IAsyncResult 를 이용함. (0) | 2014.10.30 |
---|---|
before, do, after를 묶어보자!! (0) | 2014.10.28 |
Directory.Create 관련... (0) | 2014.06.09 |
C#] 프로세스의 파일경로 읽어오기. (0) | 2014.05.30 |
가장 가까운 점 구하기 (0) | 2014.02.08 |