2016-12-09 2 views
0

I 다음 switch 문이 : 그래서리팩터링 큰 switch 문

switch (type) { 
    case 1: // 1 BYTE 8-bit unsigned integer 
    pointer = count > 4 ? offset : pointer; 
    for (let i = 0; i < count; i++) { 
     value += dataView.getUint8(pointer + i); 
    } 
    tag.value = parseInt(value, 10); 
    return tag; 
    case 3: // 3 SHORT 16-bit unsigned integer 
    pointer = count > 2 ? offset : pointer; 
    for (let i = 0; i < count; i++) { 
     value += dataView.getUint16(pointer + 2 * i, littleEnd); 
    } 
    tag.value = parseInt(value, 10); 
    return tag; 
    case 4: // 4 LONG 32-bit unsigned integer 
    pointer = count > 1 ? offset : pointer; 
    for (let i = 0; i < count; i++) { 
     value += dataView.getUint32(pointer + 4 * i, littleEnd); 
    } 
    tag.value = parseInt(value, 10); 
    return tag; 
    case 5: 
    ... 

하고 있습니다.

패턴은 약간의 변형이있을 때마다 동일합니다. 어떻게 이것을 리팩토링 할 수 있습니까? 케이스 내부의 패턴을 리팩터링하고 전체 스위치 블록을 제거하려고합니다. 그게 가능하니?

+0

나는 switch 문이 아마도 가치가 있다고 생각한다. 개별 사례 블록을 자체 함수로 끌어 와서 리팩토링을 시작합니다. 그러면 테스트 및 디버그가 더 쉬워집니다. –

+0

최소 공통 분모는 포인터를 초기화하는 것으로 보입니다. 값 + = dataView.GetSomeValue (pointerLocation, littleEnd) 태그에 대한 (i = 0, i

답변

0

는 (이 아마 코드 검토 스택 거래소에 속한다.)

을 큰 맥락의 비트 없이는 합리적인 리팩토링을 제공하거나 이러한 리팩토링는 노력과 추가 유지 보수 가치가있을 것입니다 경우에도 결정하기 어렵습니다.

요약하면 처리해야 할 숫자가 type입니다. 스위치 대신 각 유형이 작은 클래스 또는 단순한 오브젝트 인 명령 패턴을 구현할 수 있습니다. (클래스를 사용하면 스 니펫에 표시되지 않은 변수가 포함 된 "실행 컨텍스트"에서 전달하기가 약간 쉬워집니다.)

간략히하기 위해 대략적인 개요는 (매우)입니다.


기본 유형 처리기가 있습니다. 이것은 dataView 루핑 및 태그 값 설정을 마무리합니다. 컨텍스트를 알지 못하기 때문에 전달하는 컨텍스트가있는 것 같습니다. 스 니펫에 표시되지 않은 모든 변수가 포함됩니다.

(나는 당신이해야처럼 보이는 value을 포함하지 않았다,하지만 의도를 몰랐습니다.)

class BaseTypeHandler { 
    constructor(ctx) { 
    this.ctx = ctx 
    } 

    getPointer =() => throw new Error('Missing getPointer implementation') 
    getViewData =() => throw new Error('Missing getViewData implementation') 

    getValueFromDataView =() => { 
    let value = 0 

    for (let i = 0; i < this.ctx.count; i++) { 
     value += this.getViewData(i, pointer) 
    } 

    return value 
    } 

    getTag =() => { 
    const pointer = this.getPointer() 
     , value = this.getValueFromDataView() 

    this.ctx.tag.value = parseInt(value, 10) 
    return this.ctx.tag 
    } 
} 

각 서브 클래스가 얻는 방법을 여기에 필요한 고유의 기능을 구현 포인터 및 데이터를 얻는 방법 dataView. 당신이이 엄청난 숫자가없는 한 DR

을, 당신은 수학에 사용할 수 없습니다;

const typeHandlers = { 
    1: Type1Handler, 
    3: Type3Handler, 
    4: Type4Handler 
} 

const handler = new typeHandlers(type) 
    , tag = handler.getTag() 

TL :

class Type1Handler extends BaseTypeHandler { 
    getPointer =() => 
    this.ctx.count > 4 ? this.ctx.offset : this.ctx.pointer 

    getViewData = (i, pointer) => 
    this.ctx.dataView.getUint8(pointer + i) 
} 

class Type3Handler extends BaseTypeHandler { 
    getPointer =() => 
    this.ctx.count > 2 ? this.ctx.offset : this.ctx.pointer 

    getViewData = (i, pointer) => 
    this.ctx.dataView.getUint16(pointer + 2 * i, littleEnd); 
} 

그럼 당신은 타입 핸들러의 객체들을 마무리 getPointergetViewData 구현을 확인하려면 switch을 계속 사용하는 것이 좋습니다.

단순한 객체 또는 즉각적인 함수는 반드시 추론하기가 더 쉬운 것은 아니지만 상당히 작은 구현 일 수 있습니다. 또한 이미 로컬에있는 변수를 닫을 수 있다는 이점이 있습니다.

+0

이전보다 훨씬 많은 코드가 있고 논리가 재배치되기 때문에이를 구현하는 것이 큰 이점이 아닙니다. – Piu130

+0

@ Piu130에 따라 다릅니다. 이를 깨고 더 많은 유연성을 제공하고 격리 테스트를 강화할 수 있으며 올바른 클래스 또는 객체에 액세스 할 수 있는지 확인하기위한 통합 테스트가 필요합니다. * 더 많은 코드 * 또는 더 많은 코드가 필연적으로 나쁘다는 것에 동의 할 지 확신하지 못합니다. –