2013-04-14 1 views
7

사용자가 제공 한 마우스 데이터를 기반으로 기하학적 인 도형을 그리는 간단한 프로그램이 있습니다. 마우스 추적을 처리하는 클래스 (마우스 이동 기록으로 List를 가져옴)와 추상 클래스 인 Shape를 처리했습니다. 이 클래스에서 Circle, Rectangle 등과 같은 몇 가지 추가 도형을 파생시킵니다. 그리고 그 각각은 추상 Draw() 함수를 재정의합니다.과거의 폐가 원칙을 얻는 방법

모두 잘 작동하지만 원하는 모양을 수동으로 전환 할 수있게하려는 경우 문제가 발생합니다. 마우스 데이터를 얻었고 어떤 모양을 그려야하는지 알았습니다. 문제는 코드를 만들어야하는 객체를 "알"수있는 코드를 작성하고 적절한 매개 변수를 생성자에 전달하는 것입니다. 이 시점에서 새로운 Shape 파생물을 추가하는 것은 불가능합니다. 이는 맹렬히 잘못되었습니다. 내가 obiously 같은 코드로 나올 싶지 않아

:

List<Shape> Shapes = new List<Shape>(); 
// somwhere later 

if(CurrentShape == "polyline"){ 
    Shapes.Add(new Polyline(Points)); 
} 
else if (CurrentShape == "rectangle"){ 
    Shapes.Add(new Rectangle(BeginPoint, EndPoint)); 
} 
// and so on. 

명확하게 위의 코드는 오픈 폐쇄 원칙을 vilates. 문제는 그것을 극복하는 좋은 아이디어가 없다는 것입니다. 가장 큰 문제는 다른 모양의 에는 다른 매개 변수를 가진 생성자가 있기 때문에 훨씬 더 번거로운 점입니다.

저는 이것이 일반적인 문제라고 확신합니다. 그러나 나는 그것을 과거에 얻는 방법을 모르겠습니다. 아이디어가 있습니까?

+2

"공개 된 원칙"이 아닙니다. 그것은 단지 다형성입니다. –

+1

글쎄, 셰이프 클래스 코드를 에디션 용으로 닫고 확장을 위해 열어서 OCP 문제와 일치한다고 생각합니다. –

+0

당신이 진실하길 바랄뿐 아니라, 그렇지 않습니다! –

답변

3

그것은 단지 공장이 아니라 주사기가있는 공장을 요구합니다.

public class Context { 
    public Point BeginPoint; 
    public Point EndPoint; 
    public List Points; 

    whatever else 
} 

public class ShapeFactory { 

    List<FactoryWorker> workers; 

    public Shape CreateShape(string ShapeName, Context context) 
    { 
     foreach (FactoryWorker worker in workers) 
     if (worker.Accepts(ShapeName)) 
      return worker.CreateShape(context); 
    } 

    public void AddWorker(FactoryWorker worker) { 
     workers.Add(worker); 
    } 
} 

public abstract class FactortWorker { 
    public abstract bool Accepts(string ShapeName); 
    puboic Shape CreateShape(Context context); 
} 

public class PolyLineFactoryWorker : FactoryWorker { 

    public override bool Accepts(string ShapeName) { 
     return ShapeName == "polyline"; 
    } 

    public Shape CreateShape(Context context) { ... } 

} 

이 코드는 확장을 위해 열리 며 새로운 공장 근로자는 자유롭게 생성하여 공장에 추가 할 수 있습니다.

+0

안녕하세요. 다른 답변에서'string ShapeName' 매개 변수도 사용했다면,이 질문은 worker를 주입하는 대신 ShapeFactory를 확장하는 다른 대답보다 어떻게 좋은지 알고 싶습니다. – Blueriver

+0

@Blueriver :이 두 답변을 동등한 것입니다. 그러나 다른 대답으로 확장되는 공장은 없습니다. 여기의 제작자는 여기에서 나쁜 직원입니다. 공장 자체는 OCP의 폐쇄 된 부분을 깰 수 있기 때문에 절대로 수정해서는 안됩니다. –

+0

알겠습니다. 고맙습니다! – Blueriver

6

단일 클래스에서 파생되거나 동일한 인터페이스를 구현하는 객체를 만들어야하는 경우 일반적인 접근 방법 중 하나는 factory입니다. 그러나 공장 자체가 확장 가능해야하기 때문에 간단한 공장만으로는 충분하지 않을 수도 있습니다. 손이 Maker 클래스와

interface IShapeMaker { 
    IShape Make(IList<Point> points); 
} 
class RectMaker : IShapeMaker { 
    public Make(IList<Point> points) { 
     // Check if the points are good to make a rectangle 
     ... 
     if (pointsAreGoodForRectangle) { 
      return new Rectangle(...); 
     } 
     return null; // Cannot make a rectangle 
    } 
} 
class PolylineMaker : IShapeMaker { 
    public Make(IList<Point> points) { 
     // Check if the points are good to make a polyline 
     ... 
     if (pointsAreGoodForPolyline) { 
      return new Polyline(...); 
     } 
     return null; // Cannot make a polyline 
    } 
} 

, 당신은 그들에게 포인트를 통과 업체의 레지스트리 (간단한 List<IShapeMaker>) 제조 업체를 통해 이동을하고, 중지 할 수 있습니다

한 가지 방법은 다음대로 구현 널이 아닌 모양으로 돌아 왔을 때.

는 기존의 프레임 워크에 NewShapeNewShapeMaker 한 쌍을 추가하고, "그들을 연결"할 수 있기 때문에이 시스템은 확장 남아

: NewShapeMaker이 레지스트리에 도착하면, 시스템의 나머지 부분은 즉시 인식하고 사용 할 준비가됩니다 귀하의 NewShape.

+2

이 구현의 단점이있다. 여러 제조사가 동일한 점 집합을 수용 할 수 있기 때문에 갑자기 제조사의 순서가 달라진다. 공장에서 다른 모양을 반환하게합니다. 팩토리 클라이언트는 원하는 모양을 명시 적으로 나타내므로 원래 구현에는이 문제가 없습니다. 이 추가 매개 변수를 팩토리 메서드에 전달하면 쉽게 해결할 수 있습니다 (내 대답 참조). –

+0

@WiktorZychla 추가 매개 변수는 호출자에게 명시 적 제어를 제공하지만 새로운 모양을 추가하여 시스템을 확장 할 때마다 호출자를 수정할 필요가 있습니다 (예 : 호출자가 호출자의 이름을 전달하도록 "학습"해야 함). 새로운 모양이 나올 때마다 새로운 모양). 문제의 독서는 OP가 그 여분의 매개 변수를 피하고 싶어한다는 것입니다. – dasblinkenlight

+0

그는 "마우스 데이터와 그려야하는 모양을 알고 있습니다"라고 씁니다. 이것으로부터, 나는 호출자가 정확한 모양을 알고 있다고 말할 것입니다. 나는 그가 사용할 수있는 모든 모양이나 비슷한 도구 상자를 가지고 있다고 생각합니다. –

관련 문제