source

Swift Language 추상 함수

nicesource 2023. 4. 9. 21:43
반응형

Swift Language 추상 함수

나는 빠른 언어로 추상 함수를 만들고 싶다.가능합니까?

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

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

Swift에는 추상 개념(Obstractive-C 등)이 없지만 다음과 같이 할 수 있습니다.

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을 제공하지 않으면 오류가 발생합니다.

다른 동작에 base class가 계속 필요한 경우 다음을 수행할 수 있습니다.

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

이는 애플이 UIKit에서 추상적인 방법을 다루는 공식적 방식인 것 같다., 그럼 ㄴㄴㄴ데를 한 번 보세요.UITableViewController그리고 그것이 어떻게 동작하는지는UITableViewDelegate 하는 중 가 '어느 정도'라는 delegate = self「 」, 「 」

1. Put the abstract method in a protocol
protocol AbstractMethodsForClassX {
    func abstractMethod() -> String
}
2. Write your base class
/// 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. Write the Subclass(es).
/// 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!"}
}
Here is, how to you use all that
let x = ClassX()
x.doSomethingWithAbstractMethod()

출력을 확인하려면 Playground에 문의하십시오.

몇 가지 비고

  • 첫 번째, 이미 많은 답변이 있었습니다.누군가 이것까지 찾아냈으면 좋겠어요.
  • 실제로 문제는 다음과 같은 구현 패턴을 찾는 것이었습니다.
    • 클래스는 파생된 서브클래스 중 하나로 구현해야 하는 메서드를 호출합니다(오버라이드).
    • 최상의 경우 메서드가 하위 클래스에서 재정의되지 않으면 컴파일 중에 오류가 발생합니다.
  • 추상적인 메서드는 인터페이스 정의와 기본 클래스의 실제 구현의 일부라는 점입니다.둘 다 동시에.스위프트는 매우 새롭고 매우 깨끗한 정의이기 때문에, 그러한 편리함은 없고, 「불결한」개념이 있습니다(아직은.
  • 나(가난한 자바 사람)에게 이 문제는 때때로 발생한다.저는 이 게시물의 모든 답을 읽었고, 이번에는 실현 가능한 패턴을 발견했다고 생각합니다.적어도 저에게는요.
  • 업데이트: Apple의 UIKit 구현자도 동일한 패턴을 사용하는 것 같습니다. UITableViewController를 실장하다UITableViewDelegate ' 등록'은 '위임자 등록'이 합니다.delegate★★★★★★★★★★★★★★★★★★.
  • 이 모든 것은 Xcode 7.3.1의 Playground에서 테스트됩니다.

추상 베이스 클래스를 지원하는 플랫폼에서 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을 상속받아 프로토콜의 해당 부분을 충족하도록 지원하며, 프로토콜은 여전히 추상 함수를 구현하기 위해 파생 클래스를 필요로 합니다.

이 메서드의 유일한 실질적인 단점은 기본 클래스가 프로토콜을 구현하지 않기 때문에 프로토콜 속성/메서드에 액세스할 필요가 있는 기본 클래스 메서드를 가지고 있다면 파생 클래스에서 이를 재정의해야 하며 거기서부터 (슈퍼를 통해) 기본 클래스를 호출해야 한다는 것입니다.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은 프로토콜의 해당 부분을 충족하지만 파생 클래스는 여전히 상당히 간단한 방법으로 기본 클래스 로직을 공유할 수 있습니다.

이를 위한 한 가지 방법은 기본 클래스에서 정의된 선택적 닫힘을 사용하는 것입니다. 그러면 자녀는 이 닫힘을 구현할지 여부를 선택할 수 있습니다.

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")
    }
}

클래스가 하위 클래스인 경우 프로토콜은 Superclass를 따릅니다.

class SubClass: SuperClass, ProtocolOne, ProtocolTwo {}

사용.assert키워드를 지정하여 추상 메서드를 적용합니다.

class Abstract
{
    func doWork()
    {
        assert(false, "This method must be overriden by the subclass")
    }
}

class Concrete : Abstract
{
    override func doWork()
    {
        println("Did some work!")
    }
}

let abstract = Abstract()
let concrete = Concrete()

abstract.doWork()    // fails
concrete.doWork()    // OK

하지만 Steve Waddicor가 언급했듯이, 당신은 아마도 그 일을 하고 싶어할 것이다.protocol대신.

저는 질문을 이해하고 같은 해결책을 찾고 있었습니다.프로토콜은 Abstract 메서드와 다릅니다.

클래스가 이러한 프로토콜을 준수하도록 지정해야 하는 프로토콜에서 추상 메서드는 이러한 메서드를 재정의해야 함을 의미합니다.

즉, 프로토콜은 일종의 옵션입니다. 기본 클래스와 프로토콜을 지정해야 합니다. 프로토콜을 지정하지 않으면 이러한 메서드를 재정의할 필요가 없습니다.

추상 메서드는 기본 클래스를 원하지만 동일한 메서드가 아닌 고유한 메서드를 구현해야 함을 의미합니다.

나도 같은 행동이 필요해 그래서 해결책을 찾고 있었던 거야스위프트에는 그런 기능이 없는 것 같아요.

@jaumard의 제안과 비교하면 아직 단점이 있지만, 이 문제에 대한 또 다른 대안이 있습니다.그것은 반환문을 필요로 합니다.요점은 알 수 없지만, 직접 예외를 두는 것이기 때문에 다음과 같습니다.

class AbstractMethodException : NSException {

    init() {
        super.init(
            name: "Called an abstract method",
            reason: "All abstract methods must be overriden by subclasses",
            userInfo: nil
        );
    }
}

그 후:

class BaseClass {
    func abstractFunction() {
        AbstractMethodException.raise();
    }
}

그 후에 어떤 일이 일어나든 도달할 수 없기 때문에 왜 강제로 반환해야 하는지 모르겠습니다.

도움이 될지는 모르겠지만, SpritKit 게임을 만들 때 추상화된 방법에서도 비슷한 문제가 있었습니다.제가 원했던 것은 move(), run() 등의 메서드를 가진 추상 Animal 클래스입니다만, 스프라이트 이름(및 기타 기능)은 클래스 아이들에 의해 제공되어야 합니다.그래서 다음과 같은 작업을 하게 되었습니다(Swift 2에 대한 테스트 완료).

import SpriteKit

// --- Functions that must be implemented by child of Animal
public protocol InheritedAnimal
{
    func walkSpriteNames() -> [String]
    func runSpriteNames() -> [String]
}


// --- Abstract animal
public class Animal: SKNode
{
    private let inheritedAnimal: InheritedAnimal

    public init(inheritedAnimal: InheritedAnimal)
    {
        self.inheritedAnimal = inheritedAnimal
        super.init()
    }

    public required init?(coder aDecoder: NSCoder)
    {
        fatalError("NSCoding not supported")
    }

    public func walk()
    {
        let sprites = inheritedAnimal.walkSpriteNames()
        // create animation with walking sprites...
    }

    public func run()
    {
        let sprites = inheritedAnimal.runSpriteNames()
        // create animation with running sprites
    }
}


// --- Sheep
public class SheepAnimal: Animal
{
    public required init?(coder aDecoder: NSCoder)
    {
        fatalError("NSCoding not supported")
    }

    public required init()
    {
        super.init(inheritedAnimal: InheritedAnimalImpl())
    }

    private class InheritedAnimalImpl: InheritedAnimal
    {
        init() {}

        func walkSpriteNames() -> [String]
        {
            return ["sheep_step_01", "sheep_step_02", "sheep_step_03", "sheep_step_04"]
        }

        func runSpriteNames() -> [String]
        {
            return ["sheep_run_01", "sheep_run_02"]
        }
    }
}

언급URL : https://stackoverflow.com/questions/24110362/abstract-functions-in-swift-language

반응형