2016-06-27 5 views
2

현재 상황 ..유형에 더 이상 유효하지 않은 구현이 있으면 어떻게해야합니까?

은 내가 Car 인터페이스를 가지고 :

interface Car { 
    void startWith(Key key); 
    void switchGearTo(GearMode mode); 
    //.. 

    static Car newCar() { // factory 
     return new CarImpl(); 
    } 
} 

이 인터페이스를 (공장이 예제를 단축 중첩, 별도의 클래스에 존재) 구현이 있습니다

class CarImpl implements Car { 
    private Ignition ignition; 
    private GearShift gearShift; 

    public void startWith(Key key) { 
     // use ignition 
    } 

    public void switchGearTo(GearMode mode) { 
     // use gear shift 
    } 
} 

이 시점에서 Car은 응용 프로그램의 요구에 충분히 구체적이므로이 구조가 좋습니다. 더 많은 추상화가 필요 없으며 요구 사항이 충족되었으므로 YAGNI 원칙에 따라 생성되었습니다.

문제 ..

응용 프로그램의 요구 사항이 변경했으며, Car 충분히 더 이상에만 적용됩니다. SportsCar과 같은 다른 유형의 자동차가 필요합니다. 또 다른 수준의 추상화가 필요합니다.

문제는 Car은 구현이없는 추상화 수준에 불과할 때 이미 직접 구현되어 있습니다.

정적 팩토리를 제거 할 수 없거나 코드가 중단됩니다. 그러나 개발자는 더 이상 내 응용 프로그램의 필요성을 충족하지 못하기 때문에 더 이상 Car의 인스턴스를 만들 수 없어야합니다.

나의 시도 솔루션 ..

그것은 이러한 문제를 해결할 수있는 유일한 방법을 보인다는 주요 재배치를하는 것입니다. 응용 프로그램의 철학이 바뀌 었습니다. 즉 "신선한 시작"이 필요하다는 의미이며이 문제를 해결할 다른 방법은 없습니다. (나는 이것이 사실이 아니라고 희망하고있다)

나는 디폴트 차를 지정할 수 있었다. 나는 기본 차를위한 새로운 (기술적 인) 메소드를 만들어야 할 것이고, 같은 클래스에서 2 개의 메소드가 생길 것이다. 똑같은 일을 (변경없이 텔레 스코프)합니다. 이로 인해 혼란이 생기고 혼란이 생길 ​​수 있습니다. 이는 스케일링에 도움이되지 않습니다.

내 질문 ..

이 주요 재배치없이 해결 될 수있는 문제인가? 그렇지 않다면이 문제를 피하기 위해 어떻게 코드를 구성 할 수 있습니까? YAGNI가 여전히 준수하면서 요구 사항에 대한 그러한 변화를 설명 할 수 있습니까?

+3

라이브러리의 의미가 근본적으로 변경되었습니다. 생성 할 수있는 기본 자동차에 대한 개념이 없으면 (정적 메서드로 인코딩 할 수 있음) 의미 론적 변경을 반영하도록 클라이언트 코드를 업데이트 할 수 밖에 없습니다. –

+0

사용자 측에서 가능한 모든 작업이 가능하지만 사실은 그대로입니다. 일부 고객이 "Car car = Factory.newCar()"; 공장은 지금 SportCar를 돌려 줄 수 있었다. 그러나 고객은 그것을 아직도 "차"라고 부를 것이다. 어쨌든, 클라이언트의 전에는 자동차의 종류에 대해 몰랐다, 그래서 분명히 지금 코드를 업데이 트해야합니다 ... 나는 틀렸어. 아마, 당신은 깨질 클라이언트 코드의 샘플을 포함시킬 수 있습니다. – alexbt

+0

@OliverCharlseworth 앞으로 변경 될 수있는 요구 사항을 가진 애플리케이션에서 피할 수없는 문제라고 말하고 있습니까? –

답변

2

유형 구현이 더 이상 유효하지 않은 경우 일반적으로 새로운 시작을 권장하며 때로는 유일한 해결책입니다. 인터페이스이 정의 된 경우 다른 클래스가이를 구현하지 못하게 할 수 없습니다.

당신이 문제가 있어도 인터페이스 계층을 변경하면을 해결할 수 있습니다. interface Car이 더 추상적이어서 더 추상적 인 인터페이스 (interface SportsCar 등)는 interface Car으로 확장하십시오. 또한 덜 추상적 인 인터페이스를 구현하려면 class CarImpl이 필요합니다.

마지막으로 Car 인터페이스가 정의되어있는 한 다른 개발자가 Car을 인스턴스화하는 것을 중지 할 수 없습니다.

+0

사람들이 인터페이스를 구현하는 것을 막고 싶지는 않습니다. 인터페이스의 직접 구현 인스턴스를 생성하는 기능을 제거하고 싶습니다. 현재이 인터페이스는 추상화해야하므로'CarFactory # newCar()'를 통해 현재 가능합니다. 나는 더 추상적 인 필요성을 설명하는 디자인을 찾고있다. (Cornel Masson의 답변 아래 내 의견을 확인한다.) –

1

팩토리의 요점은 클라이언트 코드가 명시 적으로 특정 클래스의 인스턴스를 구성하는 것을 허용하지 않는 것과 같은 문제를 해결하는 것입니다. 이제 공장에서 CarImpl의 인스턴스가 아닌 '기본'클래스의 인스턴스를 반환해야합니다 (다른 사람들이 언급 한 것처럼). 세단 형 자동차, 또는 당신이 기본 자동차로 생각하는 것.

+0

"default car"를 선택하면 이름이 불일치하게된다. newCar()는 설명이 아니다. newCar()가 그것을 반환하더라도, newSportsCar()를 노출시켜 혼란을 야기 할 수 있습니다. 이전 버전과의 호환성은이 정도로 코드 혼잡보다 뛰어나지 만, 더 큰 시스템을 다룰 때는 지나치게 커질 수 있습니다. 자동차 하위 유형이 직접적인 impl ('SportsCarImpl','FamilyCarImpl', 10 개의 다른 하위 유형)을 갖고 있으며, 더 이상 추상화가 필요하지 않은 유형을 상상해보십시오.임씨는 그런 의미 론적 변화를 설명하기 위해 설계된 디자인을 찾고 있습니다. –

+0

@VinceEmigh - 그 밖의 어떤 것이 기대되는지는 명확하지 않습니다. - newCar()와 의미 상 유사하거나 (* something *을 반환해야하는) 메소드를 보유하거나 그렇지 않은 경우 (back-compat break). 이것은 기본적으로 논리적 인 가능성의 공간입니다. –

+0

@OliverCharlseworth 'newCar'는 무언가를 반환해야한다는 것을 알고 있습니다. 그러나 더 이상 기술적 인 방법이 아니기 때문에'newCar' 메서드 ('FamilyCar'와 같은 것을 반환 할 것입니다)를 유지할뿐만 아니라 새로운 메서드 newFamilyCar를 만들어야 만합니다. 같은 일을하는 클래스. 이것이 더 큰 규모라면, 상당히 혼란을 줄 것입니다. 나는 혼란을 피하면서이 변화를 지원하지 않도록 코드를 구조화 할 수 있었는지, 아니면 과도한 혼란없이 지금 할 수있는 방법이 있다면 –

관련 문제