2010-03-08 5 views
2

내 현재 프로젝트에는 애플리케이션 도메인의 핵심 개념을 다루는 몇 가지 데이터 클래스가 있습니다. 이제 우리 프로젝트의 일부 장소에서 구체적인 목표에 따라 다른 행동을 취해야합니다. 예 : JList는 객체 목록을 렌더링하는 작업을하지만 객체의 클래스에 따라 렌더링이 약간 다르기를 원합니다. 예 : 클래스 A의 객체는 클래스 B의 객체와 다르게 렌더링되어야하고 클래스 C는 완전히 다른 객체입니다.a로 구성된 공장. 객체의 클래스 - 어떻게 멋지게 할 것인가?

우리는 전략 클래스에서 동작을 캡슐화 한 다음 렌더링 될 객체에 적합한 클래스를 반환하는 팩토리를 갖습니다. 클라이언트 관점에서 볼 때, 괜찮습니다. 우리가 지금까지 가지고 올 수있는 모든 때문에 매우 추한 얻을 공장의 관점에서 지금

는 이미 인스턴스화 된 객체의 풀,지도도 작동합니다, 지금

if (obj instanceof classA) return strategyA; 
else if (obj instanceof classB) return strategyB; 
... 

같은 물건입니다 . 그러나 팩토리가 실제로 새 객체를 만들어야하는 경우, 우리는지도에 적합한 전략을 반환하는 팩토리/전략 객체의 다른 레이어를 해당 맵에 배치해야합니다.

이런 종류의 문제를 잘 처리하는 디자인 패턴이 있습니까?

답변

1

이렇게하는 한 가지 방법은 구현을 개체 자체에 위임하는 것입니다.

interface IRenderable { 
    public void render(); 
} 

그런 다음, 각자가 render()의 자신의 구현을 제공합니다 : 클래스가 A, BC 모두 다르게 렌더링하는 경우 예를 들어, 당신은 그들 각각이 같은 인터페이스를 구현해야 할 수도 있습니다. ListIRenderable으로 렌더링하려면 멤버를 반복하고 각각 render() 메서드 만 호출하면됩니다.

이 방법을 사용하면 명시 적으로 개체 유형을 확인할 필요가 없습니다. 어떤 클래스라도 하위 클래스로 분류되는 경우 특히 유용합니다. classA을 확장하는 classD 클래스가 있고 A과 다르게 렌더링되었다고 가정 해 보겠습니다. 지금과 같은 코드 :

if (obj instanceof classA) return strategyA; 
... 
else if (obj instanceof classD) return strategyD; 

가 실패합니다 - 당신은 항상 가장 최소한 특정 순서로 확인해야합니다. 그런 일에 대해 생각할 필요가 없다.

편집 : 귀하의 코멘트에 응답 - 당신의 목표는 모델 객체에서 프런트 엔드 코드를 유지하는 것입니다,하지만 당신은 여전히 ​​명시 적 검사를 피하려는 경우, 당신은 visitor pattern를 사용할 수 있습니다. 이 같은

뭔가 :

class Renderer { 
    public void visit(classA obj); 
    public void visit(classB obj); 
    // etc 
} 

지금

class classA { 
    public void accept(Renderer r) { 
     r.visit(this); 
    } 
} 

, 모든 렌더링 코드는 Renderer로 전환하고, 모델을 호출하는 방법을 선택하는 객체.

public interface RenderingStrategyProvider { 
    public RenderingStrategy getRenderingStrategy(); 
} 

하고 적절한 전략의 인스턴스를 돌려 :

+1

너무 빨리 답변 해 주셔서 감사합니다. 당신의 생각은 흥미 롭지 만, 모델 일 뿐인 데이터 객체가 많은 프론트 엔드 코드를 수집한다는 단점이 있습니다. 이 코드는 이식성, 코드 크기, 테스트 등과 같은 일반적인 문제를 가지고 있습니다. – xmjx

0

당신은 당신의 모델 클래스가 같은 인터페이스를 구현 할 수 있습니다. 좋아요 :

public ClassA implements RenderingStrategyProvider { 
    public RenderingStrategy getRenderingStrategy() { 
     return new ClassARenderingStrategy(this); 
     // or without this, depending on your other code 
    } 
} 

그런 경우에는 공장이 필요하지 않습니다. 또는 원한다면 하나의 메소드 호출만을 포함 할 것입니다. 그렇게하면 모델 클래스 안에 프리젠 테이션 로직이 없습니다.

또는 컨벤션 + 리플렉션을 사용할 수 있지만 이상합니다. 모델 클래스의 전략은 ModelClassStrategy 것, 당신은 할 수 있습니다 : 대신에 당신이 공장 인터페이스를 가질 수있는 경우/다른 블록의

public RenderingStrategy createRenderingStrategy(Object modelObject) { 
    return (RenderingStrategy) Class.forName(
      modelObject.getClass().getName() + "Strategy").newInstance(); 
} 
1

을,이

interface RendererFactory { 
    supports(Object obj); 
    createRenderer(Object obj); 
} 

같은 그런 당신이있을 수 있습니다 그들 중 하나가 주어진 유형을 지원하는 경우 다른 구현 목록을 요청하는 구현. 다른 구현에서는 supports 메소드에서 instanceof 검사를 수행 할 수 있습니다. 렌더러의 소비자는 createRenderer 만 호출하면됩니다.

장점 : 가능한 당신의 RendererFactories의 구성

단점 : 당신은 RendererFactories의 순서에 대해 유의해야한다 (하지만 당신은 너무/다른 경우 그렇게해야)

+0

+1. Adaptable 패턴과 유사하고 Eclipse가 요소를 UI에서 렌더링하는 데 사용하는 방식. – mhaller

1

나는 공장에서 좋아 봉사 전략 객체를 많이. 하지만 IOC처럼 취급하고 특정 유형에 대한 전략을 등록 할 수 있을지 궁금합니다. 당신은 if-else 's 무리가 없지만 그들을 등록해야합니다. 그러나 테스트 용으로도 좋을지도 모릅니다 - 모의 전략을 등록하는 '모의 공장'을 구현하는 것보다?

관련 문제