[inheritance] 스위프트 언어의 추상 함수

신속한 언어로 추상 기능을 만들고 싶습니다. 가능합니까?

class BaseClass {
    func abstractFunction() {
        // How do I force this function to be overridden?
    }
}

class SubClass : BaseClass {
    override func abstractFunction() {
        // Override
    }
}



답변

Objective-C와 같은 Swift에는 추상 개념이 없지만 다음과 같이 할 수 있습니다.

class BaseClass {
    func abstractFunction() {
        preconditionFailure("This method must be overridden") 
    } 
}

class SubClass : BaseClass {
     override func abstractFunction() {
         // Override
     } 
}


답변

당신이 원하는 것은 기본 클래스가 아니라 프로토콜입니다.

protocol MyProtocol {
    func abstractFunction()
}

class MyClass : MyProtocol {
    func abstractFunction() {
    }
}

클래스에 abstractFunction을 제공하지 않으면 오류입니다.

다른 행동을위한 기본 클래스가 여전히 필요한 경우 다음을 수행 할 수 있습니다.

class MyClass : BaseClass, MyProtocol {
    func abstractFunction() {
    }
}


답변

추상 기본 클래스를 지원하는 플랫폼에서 Swift로 상당한 양의 코드를 이식하여이를 많이 실행합니다. 진정으로 원하는 것이 추상 기본 클래스의 기능이라면,이 클래스는 공유 기반 클래스 기능의 구현 역할을하며 (그렇지 않으면 인터페이스 / 프로토콜 일뿐) 다음에 의해 구현되어야하는 메소드를 정의합니다. 파생 클래스.

Swift에서 그렇게하려면 프로토콜과 기본 클래스가 필요합니다.

protocol Thing
{
    func sharedFunction()
    func abstractFunction()
}

class BaseThing
{
    func sharedFunction()
    {
        println("All classes share this implementation")
    }
}

기본 클래스는 공유 메소드를 구현하지만 프로토콜을 구현하지는 않습니다 (모든 메소드를 구현하지는 않기 때문에).

그런 다음 파생 클래스에서 :

class DerivedThing : BaseThing, Thing 
{
    func abstractFunction() 
    {
        println("Derived classes implement this");
    }
}

파생 클래스는 기본 클래스에서 sharedFunction을 상속하여 프로토콜의 해당 부분을 만족시키는 데 도움이되며 프로토콜은 여전히 ​​파생 클래스가 abstractFunction을 구현해야합니다.

이 메소드의 유일한 단점은 기본 클래스가 프로토콜을 구현하지 않기 때문에 프로토콜 특성 / 메소드에 액세스해야하는 기본 클래스 메소드가있는 경우 파생 클래스의 메소드를 대체해야합니다. 기본 클래스가 (수퍼를 통해) 전달 self하여 기본 클래스가 작업을 수행 할 프로토콜 인스턴스 를 갖도록합니다.

예를 들어, sharedFunction이 abstractFunction을 호출해야한다고 가정하십시오. 프로토콜은 동일하게 유지되며 클래스는 다음과 같습니다.

class BaseThing
{
    func sharedFunction(thing: Thing)
    {
        println("All classes share this implementation")
        thing.abstractFunction()
    }
}

class DerivedThing : BaseThing, Thing 
{
    func sharedFunction()
    {
        super.sharedFunction(self)
    }

    func abstractFunction() 
    {
        println("Derived classes implement this");
    }
}

이제 파생 클래스의 sharedFunction은 프로토콜의 해당 부분을 만족하지만 파생 클래스는 여전히 기본 클래스 논리를 합리적으로 간단하게 공유 할 수 있습니다.


답변

이것은 Apple이 UIKit에서 추상 메소드를 처리하는 방법의 “공식적인”방법 인 것 같습니다. UITableViewController와 작동 방식을 살펴보십시오 UITableViewDelegate. 가장 먼저하는 것 중 하나는 다음 줄을 추가하는 것 delegate = self입니다. 글쎄, 그것은 정확히 속임수입니다.

1. 추상적 인 방법을 프로토콜에 넣는다

protocol AbstractMethodsForClassX {
    func abstractMethod() -> String
}

2. 기본 수업을 작성하십시오

/// It takes an implementation of the protocol as property (same like the delegate in UITableViewController does)
/// And does not implement the protocol as it does not implement the abstract methods. It has the abstract methods available in the `delegate`
class BaseClassX {
    var delegate: AbstractMethodsForClassX!

    func doSomethingWithAbstractMethod() -> String {
        return delegate.abstractMethod() + " - And I believe it"
    }
}

3. 서브 클래스를 작성하십시오.

/// First and only additional thing you have to do, you must set the "delegate" property
class ClassX: BaseClassX, AbstractMethodsForClassX {
    override init() {
        super.init()
        delegate = self
    }

    func abstractMethod() -> String {return "Yes, this works!"}
}

여기에 모든 것을 사용하는 방법이 있습니다.

let x = ClassX()
x.doSomethingWithAbstractMethod()

출력을 보려면 놀이터를 확인하십시오.

일부 비고

  • 첫째, 많은 답변이 이미 제공되었습니다. 누군가 가이 길을 찾길 바랍니다.
  • 문제는 실제로 다음을 구현하는 패턴을 찾는 것이 었습니다.
    • 클래스는 파생 서브 클래스 중 하나에서 구현되어야하는 메소드를 호출합니다 (재정의 됨).
    • 최선의 경우, 서브 클래스에서 메소드를 대체하지 않으면 컴파일 시간 동안 오류가 발생 합니다.
  • 추상 메소드에 대한 것은 인터페이스 정의와 기본 클래스의 실제 구현의 일부라는 혼합입니다. 둘 다 동시에. 스위프트는 매우 새롭고 명확하게 정의되어 있기 때문에 “아주”개념 (아직)과 같은 편의성이 없습니다.
  • 나 (빈약 한 오래된 자바 사람) 에게이 문제는 때때로 진화합니다. 나는이 게시물의 모든 답변을 읽었으며 이번에는 적어도 나에게 가능한 패턴을 발견했다고 생각합니다.
  • 업데이트 : Apple의 UIKit 구현자가 동일한 패턴을 사용하는 것처럼 보입니다. 속성 을 명시 적으로 설정하여 UITableViewController구현 UITableViewDelegate하지만 여전히 대리자로 등록해야 delegate합니다.
  • 이 모든 것은 Xcode 7.3.1의 놀이터에서 테스트되었습니다.

답변

이 작업을 수행하는 한 가지 방법은 기본 클래스에 정의 된 선택적 클로저를 사용하는 것이며 하위를 구현하도록 선택할 수 있습니다.

class BaseClass {
    var abstractClosure?:(()->())?
    func someFunc()
    {
        if let abstractClosure=abstractClosure
        {
            abstractClosure()
        }
    } 
}

class SubClass : BaseClass {
    init()
    {
        super.init()
        abstractClosure={ ..... }
    }
}


답변

글쎄, 나는 게임에 늦었고, 일어난 변화를 이용하고 있다는 것을 알고있다. 미안합니다.

어쨌든 나는 테스트를 좋아하고 fatalError()AFAIK 솔루션 은 테스트 할 수 없으며 예외가 있는 솔루션 은 테스트하기가 더 어렵 기 때문에 대답에 기여하고 싶습니다 .

빠른 접근 방식 을 사용하는 것이 좋습니다 . 귀하의 목표는 공통적 인 세부 사항을 가지고 있지만 완전히 정의되지 않은 추상화, 즉 추상 방법을 정의하는 것입니다. 추상화에서 예상되는 모든 메소드를 정의하는 프로토콜과 정의되지 않은 메소드를 모두 정의하는 프로토콜을 사용하십시오. 그런 다음 케이스에 정의 된 메소드를 구현하는 프로토콜 확장을 작성하십시오. 마지막으로 파생 클래스는 프로토콜을 구현해야합니다. 이는 모든 메서드를 의미하지만 프로토콜 확장의 일부인 메서드는 이미 구현되어 있습니다.

하나의 구체적인 함수로 예제를 확장하십시오.

protocol BaseAbstraction {
    func abstractFunction() {
        // How do I force this function to be overridden?
    }
}

extension BaseAbstraction {
    func definedFunction() {
        print("Hello")
}

class SubClass : BaseAbstraction {
    func abstractFunction() {
        // No need to "Override". Just implement.
    }
}

이렇게하면 컴파일러가 다시 친구가됩니다. 메소드가 “재정의되지 않은”경우 컴파일시 오류 fatalError()가 발생하거나 런타임에 발생할 수있는 예외 대신 컴파일 오류 가 발생합니다.


답변

나는 당신이 지금하고있는 일을 이해합니다. 프로토콜을 사용하는 것이 더 나을 것이라고 생각합니다

protocol BaseProtocol {
    func abstractFunction()
}

그런 다음 프로토콜을 따르십시오.

class SubClass : BaseProtocol {

    func abstractFunction() {
        // Override
        println("Override")
    }
}

클래스가 서브 클래스 인 경우 프로토콜은 수퍼 클래스를 따릅니다.

class SubClass: SuperClass, ProtocolOne, ProtocolTwo {}