분류 전체보기 (328)
.NET (111)
S/W tip (35)
etc (63)
DB (34)
HOT item~! (48)
Disign pettens (4)
UX (6)
나의 S/W (2)
개발관련 이슈 (16)
Diary (1)
웹플러스 (1)
calendar
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
tags
archive
link
ColorSwitch 00 01 02
출처 :
http://vandbt.tistory.com/42#recentTrackback

 포스트의 주제는 이전의 S.O.L.I.D 의  LSP에 이어 의존 역전의 원칙 Dependency Inversion Principle (DIP) 입니다. 포스팅의 동기 또한 LSP의 동기와 같습니다. 개념이해를 돕기  위해 뽑아낸 간략화된 핵심 정의가, 오히려 상세 이해를 방해함을 느꼈습니다. 원칙의 정의만으로는 그 원칙이 의미하는 바를 정확히 이해하기 어렵습니다. 이 포스트는 DIP 원칙이 의미를 설명하는 것입니다. 원칙의 상세를 이해하고, 핵심 정의 구문은 기억을 끄집어 내기위한 실마리로 삼는 것이 가장 좋을 것입니다.

이제 의존 관계 역전의 원칙 DIP :  Dependency Inversion Principle 을 시작하도록 합시다.

먼저 원칙의 이름으로 부터 어떤 원칙인지 힌트를 얻어 보도록 하겠습니다. "의존 관계를 역전 하라는 이야기군, 가만 의존이 뭐지?"


의존이란 무엇인가?

객체-지향 프로그램은 관계를 가지고 있는 객체의 집합 그 자체 입니다. 그 관계를 UML의하면 Multiplicity, Aggregation, Composition, Dependency  4가지의 형태로 일반화 할 수 있습니다. Inheritance 는 종류가 다른 관계라고 생각하도록 하죠.  단순화 하면 객체A 가 객체B를 포함하고 있는데, 그 형태가 위에 언급한 형태 중 하나라는 것이며, 이때 객체A가 객체B를 의존하고 있다 라고 일반화 시켜 말합니다.



의존을 알았으니 추측을 넘어, DIP 의 정의를 알아 보도록 하겠습니다.

A. 고차원의 모듈은 저차원의 모듈에 의존하면 안된다. 이 두 모듈 모두 다른 추상화된 것에 의존 해야 한다.

B. 추상화 된 것은 구체적인 것에 의존하면 안 된다. 구체적인 것이 추상화된 것에 의존해야 한다.


더 쉽게 말할 수도 있다. 자주 변경되는 컨크리트 클래스에 의존하지 마라. 만약 어떤 클래스의 참조를 가져야 한다면, 참조 대상이 되는 클래스를 추상 클래스로 만들어라. 만약 어떤 함수를 호출해야 한다면, 호출 되는 함수를 추상 함수로 만들어라.

일반적으로, 추상 클래스와 인터페이스는 자신에게서 유도된 구체적인 클래스 보다 훨씬 덜 변한다.

Java 프로그래머를 위한 UML 실전에서는 이것만 쓴다!. 로버트 C.마틴 지음 / 이용원, 정지호 옮김, 인사이트 출판사, p140, 141 


음... 가능한 추상 클래스나 인터페이스를 참조 함으로써 의존을 좀더 느슨하게 만들어라는 얘기군. 알겠어, 앞으로는 최대한 추상 클래스를 만들고, 인터페이스를 끄집어 내서 DIP 를 지키는 개발자가 되겠어!  근데 관계의 역전은 뭘 의미하는 거지? 위의 정의에 역전이라는 말은 언급되지도 안잖아, 에이 머리 아파~ 이 정도만 이해하면 되겠지.

관계의 역전의 뜻에 대해 의문점을 남긴채 찜찜한 상태로 공부를 마무리 하게 됩니다.




자! 이제부터 시작입니다. 역전은 뭘 말하는 걸까요?. DIP 의 성배를 찾으러 갑시다.


DIP를 제시한 로버트 C. 마틴보다 더 잘 설명할 능력이 부족하기도 하고, 지금까지 읽은 문서중 가장 잘 설명하고 있다고 생각하는 마틴의 DIP 문서의 요약 및 해석으로 글을 쓰도록 하겠습니다.



의존 관계 역전의 원칙 The Dependency Inversion Principle 


이전 글에서 Liskov Substitution Principle LSP 에 대해 이야기 했습니다. LSP는 C++ 에서 상속을 사용할 때 일반적인 가이드를 제공하는 것입니다.  파생되는 클래스는 기반 클래스의 가상 멤버 함수의 약속이 파생 클래스에서도 제공되어 져야 한다는 것이고, 이를 위반할 경우 객체의 적절한 작동을 보장하기 위해서는  실제 객체의 타입을 확인해야 절차가 유발되며, 이 행위는 OCP를 위반하게 된다 였습니다.

우리는 OCP 와 LSP를 논했고, 이 원칙들이 엄격하게 지켜져서 얻어지는 구조를 일반화 시킬수가 있는데, 이 구조를 "의존 관계 역전의 원칙 The Dependency Inversion Principle" 이라고 이름 붙이겠습니다.


소프트웨어에 뭐가 잘못 되어가고 있는가? What goes wrong with software?

우리 대부분은 "나쁜 디자인"의 소프트웨어 조각으로 일을 해본 유쾌하지 않은 경험을 가지고 있습니다. 우리중 일부는 그 "나쁜 디자인"의 주인이 자기 자신이었다는 것을 발견하는 더욱 나쁜 경험을 가지고 있을지도 모릅니다. 도대체 디자인을 나쁘게 만드는 것은 무엇일까요?


"나쁜 디자인"의 정의 The Definition of a "Bad Design"

여러분은 다른 사람들에게 자신이 특별히 자랑스러워하는 소프트웨어 디자인을  발표해 본적이 있습니까?  그때 "왜 그런 방법으로 하셨나요?" 라는 말을 들어 본적이 있습니까? 이건 저에게 일어난 일이고, 또 많은 엔지니어들에도 벌이지고 있는 일입니다. 디자인에 동의하지 않는 엔니지어는 "나쁜 디자인"에 대한 정의에 대해 나와 동일한 기준을 가지고 있지 않았습니다. 엔지니어들에게서 발견한 가장 일반적인 기준은 "나는 그런 방법으로 하지 않아" 였습니다.

하지만, 모든 엔지니어들이 동의하는 나쁜 디자인에 대한 기준이 있었으니 다음과 같습니다.

1. 모든 변경마다 많은 다른 부분에 영향을 미쳐 변경 자체가 어렵다. (Rigidity)
2. 변경 작업을 할때 예상치 못한 다른 부분이 망가진다. (Fragility)
3. 현재의 어플리케이션에서 분리할 수 없기 때문에 다른 어플리케이션에서 재사용 하기가 매우 어렵다. (Immobility)

그 외에도 유연성, 견고성 과 같은 설명하기 어려운 요소들이 있었습니다. 따라서 위의 세가지 항목을 "좋고, 나쁨의" 기준으로 삼기로 결정 했습니다.


 "나쁜 디자인"의 원인 The Cause of "Bad Design"

무엇이 디자인을 딱딱하고 rigid, 깨지기 쉽고 fragile, 이동할 수 없게 immobile 만드는 것일까? 그건 모듈 디자인의 상호의존 interdependence 때문입니다. 

변경이 어려운 rigidity 디자인 원인은 강하게 상호의존하고 있는 부분의 단일 변경이 그가 의존하는 모듈에게 연쇄변경을 요구하기 때문입니다. 이러한 일련의 변경이 확장되면 설계자와 유지관리자는 그를 예측, 추정하지 못합니다. 이는 변경 승인을 주저하게 만들고, 디자인은 공식적으로 경화 되었다라고 선언 됩니다.

깨지기 쉬움 fragility 이란 단일 변경의 영향으로 매우 많은 부분이 고장남을 뜻합니다. 개념적으로 관련이 없는 영역에서도 종종 새로운 문제가 발생합니다. 이런 깨지기 쉬움은 설계와 관리조직의 신뢰성을 급격히  떨어트립니다. 사용자와 관리자는 상품의 품질을 예상할 수 없게 됩니다. 한 부분의 간단한 변경이 그와 명백히 관련이 없는 부분에서 실패를 만들어 냅니다. 이런 문제를 해결하는 일 자체는 더욱 문제로 부상합니다. 유지보수 프로세스가 자신의 꼬리를 쫒는 개와 닮았거든요.

이동 불가능한 immobile 디자인이란 이동을 희망하는 어떠한 부분이 원치 않는 다른 부분의 상세를 강력하게 의존하고  있는 것을 말합니다. 디자이너는 새로운 어플리이션에 재사용 될 수 있는지 기존 어플리케이션을 조사 합니다. 이동시키고 싶은 부분을 분리하기 위해 매우 많은 부분으로 부터 분리해야 한다면, 대부분 그러한 디자인은 새로 개발하는 것보다 비용이 높기 때문에 재사용될 수 없습니다.



의존 관계 역전의 원칙 The Dependency Inversion Principle


A. 하이 레벨 모듈은 로우레벨 모듈에 의존해서는 안된다. 둘다 추상에 의존해야 한다.

B. 추상은 상세를 의존해서는 안된다. 상세는 추상을 의존해야 한다.

A. HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS.

B. ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS.


Copy 모듈은 Keyboard 와 Printer 디바이스의 상세를 사용합니다. - 구조적 디자인의 예



내가 왜 "역전 inversion" 이라는 단어를 사용했는지 의문이 생길 겁니다. 바로 구조적 분석, 구조적 디자인으로 대표되는 전통적인 개발 방법 때문입니다.  하이 레벨 모듈이 로우 레벨 모듈을 의존하는 구조, 추상이 상세를 의존하는 구조적 디자인 말이죠. 전통적 설계의 목적은 하이 레벨 모듈이 로우 레벨 모듈을 어떻게 호출할 것인지의 서브프로그램 구조를 정의하는 것 입니다.  [그림 1 ]은 구조적 디자인 구조의 좋은 예 입니다. 그래서 잘 설계된 객체-지향 프로그램의 의존 구조는 전통적 절차적 메소드의 결과로 만들어지는 의존 구조를 "역전 invert"한 형태 입니다.


 하이 레벨 모듈이 로우 레벨 모듈을 의존하고 있는 경우를 고려해 봅시다. 하이 레벨 모듈은 어플리케이션의 중요한 정책 결정과 비즈니스 모델을 담고 있습니다. 모델은 어플리케이션의 정체성을 담고 있죠. 이 모듈들이 로우 레벨 모듈을 의존하고 있고, 로우 레벨 모듈에서 발생하는 변경은 하이 레벨 모듈들에 직접적인 영향을 미치며 마침내 변경을 강요합니다.


이건 완전히 말이 안되는 상황입니다. 변경을 강요해야 하는 것은 하이 레벨 모듈이어야 하며, 하이 레벨 모듈이 로우 레벨의 상급자가 되어야 합니다. 어떤 상황이건 하이 레벨 모듈이 로우 레벨 모듈을 의존 해서는 안됩니다.

더 나아가, 하이 레벨 모듈은 재사용 가능해야 합니다. 우리는 이미 서브루틴 라이브러리와 같은 형태로 로우 레벨 모듈을 재사용하는데 정통해 있습니다. 하이 레벨 모듈이 로우 레벨 모듈을 의존하고 있으면, 하이 레벨 모듈은 문맥이 다른 곳에 재사용되기 어려워 집니다. 그러나, 하이 레벨 모듈이 로우 레벨 모듈에 독립적 이라면, 하이 레벨 모듈은 매우 간단히 재사용 될 수 있습니다. 이것이 바로 프레임워크 디자인의 핵심 입니다.
 



레이어링 Layering

Booch 에 따르면 " 잘 구조화된 객체-지향 아키텍처는 명확하게 정의된 레이어를 가지고 있다. 개개의 레이어는 잘-정의 되고, 통제되는 인터페이스를 통해 응집성 있는 서비스의 집합을 제공한다." 이 문장을 순진하게 해석한 디자이너가 만들어내는 구조는 [그림 3] 과 같을 것입니다. 이 다이어그램에서 하이 레벨 정책 클래스는 로워 레벨 메커니즘을 사용합니다. 이는 상세 레벨의 유틸리티 클래스를 사용하는 형태로 변합니다.  정책 레이어가 변경에 민감해서 유틸리티 레이어에 변경이 전파되는 교활한 특성을 보이더라도 괜찮지만, 의존은 전이적 transitive 입니다. 정책 레이어는 유틸리티 레이어를 의존하는 그 어떤 것(여기서는 메커니즘 레이어)에 의존하고 있습니다.  그래서 정책 레이어는 유틸리티 레이어를 의존하는 불행한 형태가 됩니다.




[그림 4] 는 보다 좋은 모델입니다. 각각의 로워 레벨 레이어들이 추상 클래스로 표현되고 있습니다. 실체 레이어는 추상레이어로 부터 파생 됩니다. 각각의 하이 레벨 레이어는 추상 인터페이스를 이용해 다음 단계의 로워 레벨 레이어를 사용합니다. 따라서 레이어들은 다른 레이어들을 의존하는 대신에 추상 클래스를 의존합니다. 정책 레이어의 의존이 전이되면 유틸리티 레이어만을 망가뜨리는 것이 아닙니다. 정책 레이어가  직접적으로 의존하고 있는 메커니즘 레이어 조차도 망가뜨립니다. 


이 모델을 사용하면 정책 레이어는 메커니즘 레이어나 유틸리티 레이어의 변경으로 부터 영향을 받지   않습니다. 더 나아가,  정책 레이어는 메커니즘 레이어의 인터페이스를 준수하는 로워 레벨 모듈의 정의를 가진 다른 문맥에서 재사용 될 수 있습니다. 의존을 역전시킴으로써 우리는 좀더 유연하고, 견고하고, 이동성 있는 구조를 만들 수 있습니다.


단순한 예제 Simple Example

의존 역전은 한 클래스가 다른 클래스에 메시지를 보낼때 적용할 수 있습니다. button 객체와 lamp 객체를 생각해 보세요. 

button 객체는 외부 환경을 감지하고, 사용자가 버튼을 눌렀는지 여부를 결정합니다. lamp 객체는 외부 환경으로 부터 영향을 받습니다. TurnOn 메시지를 받으면 불을 밝히고, TurnOff 메시지를 받으면 불을 끕니다.

 button 객체가 lamp 객체를 제어하는 시스템을 어떻게 설계할까요?

Figure 5는 이를 구현한 순진한 모델입니다. 

button 객체는 lamp 객체에게 TurnOn, TurnOff 메시지를 보냅니다.  button 클래스는 lamp 클래스 인스턴스와 관계를 가지기 위해서 lamp를 "포함" 합니다. 

 


위 모델의 구현은 아래와 같습니다.

Figure 5 는 의존 관계 역전의 원칙을 위반합니다. 어플리케이션의 하이-레벨 정책이 로우-레벨 모듈과 분리되지 않았습니다. : 추상과 상세가 분리되지 않았다는 말입니다. 분리하지 않으면 하이-레벨 정책이 자동적으로 로우-레벨 모듈을 의존합니다. 추상이 상세를 자동적으로 의존하는 것입니다.


[전통적인 button/lamp model 구현 코드]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
namespace TradButtonModel
{
    class Lamp{
        public void TurnOn()
        {
            Console.WriteLine("Trad Lamp 램프를 켭니다.");
        }
        public void TurnOff()
        {
            Console.WriteLine("Trad Lamp 램프를 끕니다.");
        }
    }
  
    class Button {
        private Lamp itsLamp;
  
        public Button(Lamp lamp)
        {
            this.itsLamp = lamp;
        }
  
        public void Detect()
        {
            bool buttonOn = GetPhysicalState();
            if (buttonOn)
            {
                itsLamp.TurnOn();
            }
            else
            {
                itsLamp.TurnOff();
            }
        }
  
        private bool GetPhysicalState()
        {
            bool isPressed = false;
            //물리적 장치가 눌려저 있으면 true 를 반환
            return isPressed;
        }
    }
  
  
  
}

의존 하는 추상 찾기 Finding the Underlying Abstraction

하이 레벨 정책이란 무엇일까요? 이것은 어플리케이션이 의존하는 추상입니다. 상세가 변한다 해도 변경되지 않는 것을 의미하죠. Button/Lamp 예제에서 의존하는 추상이란 사용자의 on/off 제스처를 감지하고 타겟 객체에게 전달하는 것을 의미합니다. 말도 안됩니다!, 타겟 객체는 또 뭐죠? 타겟 객체는 추상에 영향을 주지 않는 상세 입니다.

의존 관계 역전의 원칙을 적용하려면 문제의 상세로부터 추상을 분리해야 합니다. 그런 다음, 추상이 상세를 의존하는 Figure 5 를 Figure 6 와 같이 변경할 수 있습니다.



Figure 6, 우리는 button 클래스의 상세 구현으로 부터 추상을 격리하였습니다. 


상위 레벨 정책이 완전히 추상 button 클래스만을 가지고 있음을 주목하세요. Button 클래스는 사용자   제스처를 감지하는 물리적 메커니즘을 전혀 모릅니다. 그리고, Lamp 에 대해서도 전혀 모릅니다. 

이 상세들은 추상을 구현한 ButtonImplementation, Lamp 클래스에 의해 추상으로 부터 격리됩니다. 


[DIP를 적용한 button/lamp model 구현 코드] 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
namespace InvertedButtonModel
{
    abstract class ButtonClient
    {
        public abstract void TurnOn();
        public abstract void TurnOff();
    }
  
  
    class Lamp : ButtonClient
    {
        public override void TurnOn()
        {
            Console.WriteLine("Lamp 램프를 켭니다.");
        }
  
        public override void TurnOff()
        {
            Console.WriteLine("Lamp 램프를 끕니다.");
        }
    }
  
  
    abstract class Button
    {
        private ButtonClient buttonClient;
  
        public Button(ButtonClient client)
        {
            this.buttonClient = client;
        }
        public void Detect()
        {
            bool buttonOn = GetState();
            if (buttonOn)
            {
                buttonClient.TurnOn();
            }
            else
            {
                buttonClient.TurnOff();
            }
        }
        public abstract bool GetState();
  
  
    }
  
    class ButtonImplementation : Button
    {
        public ButtonImplementation(ButtonClient client):base(client){}
  
        public override bool GetState(){
            bool isPressed = false;
            //물리적 장치를 감지하여 반환
            return isPressed;
        }
  
    }
}


결론 Conclusion

의존 관계 역전의 원칙은 객체-지향 기술이 주장하는 장점의 근원입니다. 좋은 어플리케이션은 재사용 가능한 프레임워크를 만들길 요구합니다. 변경에 강한 코드의 구조를 만드는 것은 매우 중요 합니다. 그리고, 추상과 상세를 서로 격리시키기 때문에 코드 관리는 더욱 쉬워 집니다.

의존 관계의 역전 dependency inversion  이란 구조적 디자인에서 발생하던 로워 레벨 모듈의 변경이 하이 레벨 모듈의 변경을 요구는 위계의 관계를 끊자 라는 의미로 쓰여진 역전입니다. 실제의 사용 관계는 바뀌지 않으며, 추상을 매개로 메시지를 주고 받음으로써 관계를 최대한 느슨하게 만들어야 한다는 원칙입니다.

구현 관점에서 추상 클래스, 인터페이스를 사용하는 것부터 시작하여, 아키텍처 관점까지 확장할 수 있습니다. 예를 들어,  데이터베이스를 연결하는 레이어로 OLEDB를 사용한다면, OLEDB의 인터페이스를 제공하는 물리 DB가  MSSQL 에서 ORACLE 로의 변경되더라도 그 변경이 상위로 전파되지 않는다 라고 이해 할 수 있습니다.
 


하이 레벨과 로워레벨 사이에 추상을 삽입함으로써 로워 레벨의 변경이 하이 레벨로 전파되는 것을 막는다.



끝으로, 


"A. 하이 레벨 모듈은 로우레벨 모듈에 의존해서는 안된다. 둘다 추상에 의존해야 한다." 라는 정의는  "A. 하이 레벨 모듈은 로우레벨 모듈에 의존해서는 안된다 의존 하되, 둘다 추상에 의존해야 한다." 로 해석하는 것이 혼란을 피하는 것이라 생각됩니다.


### 끝.


참고자료 : 
로버트 C. 마틴 The Dependency Inversion Principle.pdf [Martin96] Robert C. Martin, Engineering Notebook, C++ Report
 


책 : java 프로그래머를 위한 UML 실전에서는 이것만 쓴다!. 로버트 C.마틴 지음 / 이용원, 정지호 옮김, 인사이트 출판사, p140,p141 

 






출처 프로그래머 일지 | 아톰
원문 http://blog.naver.com/slowxslow/120001396701

GoF의 디자인패턴을 C# 으로 구현했습니다.

 

Software Design Patterns

Design patterns are recurring solutions to software design problems you find again and again in real-world application development. Design patterns are about design and interaction of objects, as well as providing a communication platform concerning elegant, reusable solutions to commonly encountered programming challenges.

The Gang of Four (GOF) patterns are generally considered the foundation for all other patterns. They are categorized in three groups: Creational, Structural, and Behavioral. Here you will find information on these patterns together with downloadable source code in C#.

To give you a head start, the source code is provided in two forms: structural and real-world. Structural code uses type names as defined in the pattern definition and UML diagrams. Real-world code provides real-world programming situations where you may use the patterns. Let us know if you find these useful.

  Creational Patterns
  Abstract Factory   Creates an instance of several families of classes
  Builder   Separates object construction from its representation
  Factory Method   Creates an instance of several derived classes
  Prototype   A fully initialized instance to be copied or cloned
  Singleton   A class of which only a single instance can exist

  Structural Patterns
  Adapter   Match interfaces of different classes
  Bridge   Separates an object’s interface from its implementation
  Composite   A tree structure of simple and composite objects
  Decorator   Add responsibilities to objects dynamically
  Façade   A single class that represents an entire subsystem
  Flyweight   A fine-grained instance used for efficient sharing
  Proxy   An object representing another object

  Behavioral Patterns
  Chain of Resp.   A way of passing a request between a chain of objects
  Command   Encapsulate a command request as an object
  Interpreter   A way to include language elements in a program
  Iterator   Sequentially access the elements of a collection
  Mediator   Defines simplified communication between classes
  Memento   Capture and restore an object's internal state
  Observer   A way of notifying change to a number of classes
  State   Alter an object's behavior when its state changes
  Strategy   Encapsulates an algorithm inside a class
  Template Method   Defer the exact steps of an algorithm to a subclass
  Visitor   Defines a new operation to a class without change

 

[출처]

http://www.dofactory.com/Patterns/Patterns.aspx



정말 갖고 싶은 자전거다 ㅜㅜ

http://www.montaguekorea.com/

아.......

20D Black을 사러갔는데.....없단다...ㅠ_ㅠ

결국 70V Black 을 30% 할인된 가격에 구입!!!(1,120,000)

근데 생각보다 자전거가 너무 무겁다....

원래 쓰던 녀석이 이쁘고 가벼워서... 차이가 많이 나는데...

프레임이 원래 무거워서 그런건가...? 아니면 부품들을 싹 바꾸면 괜찮아지려나~? ㅋ

 
SwissBike 20D black
스위스바이크 20D(Matt Black)
2,100,000 원
 
SwissBike 20D brush
스위스바이크 20D(Brush Aluminum)
2,100,000 원
 
SwissBike TX20D brush
스위스바이크 TX20D(Brush Aluminum)
2,100,000 원
 
SwissBike SE
SwissBike SE
3,600,000 원
 
스위스바이크 LXV
스위스바이크 LXV(정찰제)
1,450,000 원
 
SwissBike X90
SwissBike X90
3,200,000 원
 
SwissBike X70
SwissBike X70
1,500,000 원
 
SwissBike X50
SwissBike X50
750,000 원
 
Paratrooper PRO
Paratrooper PRO
1,350,000 원
 
Paratrooper24
Paratrooper24
1,150,000 원
 
SwissBike 60D black
스위스바이크 60D(Matt Black)
1,750,000 원
 
SwissBike 60D brush
스위스바이크 60D(Brush Aluminum)
1,750,000 원
 
SwissBike TX60D brush
스위스바이크 TX60D(Brush Aluminum)
1,750,000 원
 
SwissBike 70V black
스위스바이크 70V(Matt Black)
1,550,000 원
 
SwissBike 70V brush
스위스바이크 70V(Brush Aluminum)
1,550,000 원
 
SwissBike TX70V brush
스위스바이크 TX70V(Brush Aluminum)
1,550,000 원
 
Paratrooper 70V green
PARATROOPER 70V Cammy Green
1,550,000 원
 
Paratrooper20D green
PARATROOPER 20D Cammy Green
2,100,000 원
 
Paratrooper 60D green
PARATROOPER 60D Cammy Green
1,750,000 원
 
CX orange
CX 21-SPEED COMFORT BIKE
800,000 원
 
Paratrooper 70V brown
PARATROOPER 70V Matt Brown
1,550,000 원
 
Paratrooper 20D brown
PARATROOPER 20D Matt Brown
2,100,000 원
 
BOSTON
BOSTON
950,000 원
 
FIT
FIT
1,600,000 원
 
Paratrooper 60D brown
PARATROOPER 60D Matt Brown
1,750,000 원
 
BOSTON™ 8
BOSTON™ 8
1,400,000 원
 
CROSSTOWN
CROSSTOWN
800,000 원
 
NAVIGATOR
NAVIGATOR
1,200,000 원
 


articles
recent replies
recent trackbacks
notice
Admin : New post