2017-11-30 1 views
2

가짜 시나리오 :Swift 프로토콜 확장을 사용하여 개인 속성을 수정할 수있는 공유 코드를 만드는 방법은 무엇입니까?

클래스가 있습니다 : ClassA; 및 ClassB. 둘 다 이라는 단일 요구 사항을 포함하는 ProtocolC을 구현합니다. ProtocolC은 및 ClassB이 요구하는 기능이 동일하기 때문에 createKey()을 구현하는 extension을 가지고 있습니다. 그러나 createKey()의 구현은 이라는 개인 변수에 액세스해야합니다. 이는 ClassAClassB이 모두 포함되어 있으며 두 클래스에서 서로 다른 값을 가져야합니다 (상상해보십시오). 변수가 fileprivate이기 때문에 extensioncreateKey() 인 경우 ProtocolC이됩니다. 이는 해당 코드가 ClassAClassB 모두에 복제되어야 함을 의미하기 때문에 유용하지 않습니다. 그러나 중복 된 코드는 프로그래밍의 no-no입니다. 프록시 은 프로토콜 확장이 아닌 수퍼 클래스를 사용하는 일 수 있지만 스위프트가 달성하려고 시도하는 것과는 다른 결과를 가져옵니다. 상속은 신속한 아니오입니다.

// the ideal: 

class ClassA: ProtocolC { 
    fileprivate var uniqueKey: String? 
} 

class ClassB: ProtocolC { 
    fileprivate var uniqueKey: String? 
} 

protocol ProtocolC { 
    func createKey() 
} 

extension ProtocolC { 
    func createKey(){ 
     uniqueKey = NSUUID().uuidString 
    } 
} 



// the reality: 

class ClassA: ProtocolC { 
    fileprivate var uniqueKey: String? 
    func createKey(){ 
     uniqueKey = NSUUID().uuidString 
    } 
} 

class ClassB: ProtocolC { 
    fileprivate var uniqueKey: String? 
    func createKey(){ 
     uniqueKey = NSUUID().uuidString 
    } 
} 

uniqueKey

는 설정할 수도없는에서 getTable이 아니라 두 개의 클래스, 내부에 고정 될 필요가있다. 신속한 작성의 해결책은 무엇입니까? 개인 속성에 액세스 할 수있는 일반 코드. 상속을 피하는 동안?

읽어 주셔서 감사합니다.

+0

제안 사항이 없습니다. 나는 다음과 같이 줄 것이다 : 중복 된 코드; 또는 상속을 사용합니까? 그것은 실패한 것 같은 느낌입니다. –

+0

이 질문은 탐구/학습을위한 것이지만, 실용적인 방법으로이 예제를 해결하기 위해서는'fileprivate var uniqueKey : String? = NSUUID() .uuidString' 두 파일 사이. – Connor

+0

나는 결국 @ 코 너를했다. 내가 실패한 것처럼 느껴졌고 가장 좋지 않은 방법으로 해결책을 찾았습니다. 여전히 그렇습니다. 하지만 ... 정확히 무엇을해야합니까? 나는 모른다. –

답변

2

다음은 이상적인 아이디어에 가깝습니다. 단점은 확장 메서드에 캐스팅 런타임 프로토콜이지만, 프로토콜 확장을 통해 액세스 제어 당신이 찾고있는 (fileprivate 저장 VAR)과 코드 재사용의 수준을 모두 수행 :

fileprivate protocol UniqueKeyDefining { 
    var uniqueKey: String? { get set } 
} 

class ClassA: ProtocolC, UniqueKeyDefining { 
    fileprivate var uniqueKey: String? 
} 

class ClassB: ProtocolC, UniqueKeyDefining { 
    fileprivate var uniqueKey: String? 
} 

protocol ProtocolC { 
    func createKey() 
} 

extension ProtocolC { 
    func createKey(){ 
     if var hasUniqueKey = self as? UniqueKeyDefining { 
      hasUniqueKey.uniqueKey = NSUUID().uuidString 
     } else { 
      // Some default behavior if the conformer to ProtocolC isn't also UniqueKeyDefining 
     } 
    } 
} 

프로토콜 UniqueKeyDefining ISN ' ClassAClassB으로 선언 된 파일 외부에서 볼 수 있으므로 파일 외부의 코드는 해당 클래스가 해당 클래스를 준수하거나 해당 uniqueKey ivars에 대한 가시성을 가지고 있음을 알 수 없습니다. 이 에 대한 UniqueKeyDefining 알고 않도록

ProtocolC의 특정 프로토콜의 확장, 같은 파일에 선언하고 조건이 fileprivate 프로토콜을 통해 uniqueKey 바르에 액세스하려면 런타임에 해당 프로토콜에 self을 시전 할 수 있습니다.

이 파일 외부의 클래스에서는 확장 성이 뛰어나거나 재사용 할 수 없지만 귀하의 질문에서 해석 한 좁은 요구 사항을 충족합니다.

+0

Nice @ daniel-hall, 나는 그 프로토콜이 분명히 도움이 될 수 있다는 것을 몰랐다. –

+0

마지막 확장자를 제한하지 않는 이유는 무엇입니까? '확장 프로토콜 C 어디에서 Self : UniqueKeyDefining' – DeFrenZ

+0

@DeFrenZ - 그 확장은 내부적으로/공개적으로 파일 외부에서 보이지 않을 것이기 때문에. 내 생각에'createKey()'를 정의하고 내부적으로 또는 공개적으로 호출 할 수있는 반면, 고유 한 클래스의 uniqueKey' var를 사용합니다. –

1

프로토콜에 정의되지 않은 항목에 액세스하려고합니다. 확장 프로그램은 공개 된 세부 사항만을 기반으로합니다. 당신은 사적인 사람에게 접근해서는 안됩니다.

저는 실제로 액세스 제어 및 유형 시스템과의 전투보다는 "공유 구현"이라고 생각합니다. 구현을 공유해야하는 경우 명시 적으로 구현하고 공유하십시오.개인 세부 사항에

protocol ProtocolC { 
    func createKey() 
} 

class ClassA: ProtocolC { 
    private var impl = Impl() 
    func createKey() { 
     impl.createKey() 
    } 
} 

class ClassB: ProtocolC { 
    private var impl = Impl() 
    func createKey() { 
     impl.createKey() 
    } 
} 

private struct Impl { 
    private(set) var uniqueKey: String? 
    mutating func createKey(){ 
     // Lock here. 
     uniqueKey = NSUUID().uuidString 
     // Unlock here. 
    } 
} 

방지 의존성이 의도와 extension의 설계 목표와 같은 의존성이 코드가 취약하기 때문에 중 하나이며, 이러한 취약성은 하위 클래스의 주요 문제 중 하나입니다.

+0

감사합니다. @eonil. 나는 내가 요구하는 질문이 불가능하다는 것을 안다. 난 그냥 상속 대신 프로토콜/컴포지션을 사용하여 반복 된 코드를 피하는 노력하고 있습니다. 귀하의 예제는 좋지만 코드를 반복합니다! 글자 A와 B 이외에 두 클래스가 동일합니다! 나는 "이상적인 세계"에서'uniqueKey = NSUUID() .uuidString' * once * somewhere *와 그 밖의 아무것도 쓰지 말아야한다고 생각합니다. 하지만 아마도 이것은 가능하지 않습니다. –

+1

@TheMotherofJosephBeuys "약간의 복사가 약간의 의존성보다 낫습니다." - Rob Pike, https://go-proverbs.github.io – Eonil

+0

@TheMotherofJosephBeuys 또한 'uniqueKey = NSUUID() .uuidString' 코드는 실제로 예제에서는 한 번만 표시됩니다. 다른 부분을 구성하는 방법은 사용자에게 달려 있습니다. – Eonil

관련 문제