2016-11-23 5 views
5

私はSwift 2.2で訪問者のパターンを仕事中のプロジェクトに実装しています。Swiftのビジターパターンで定型文を減らすにはどうすればよいですか?

私はソースコードを沸かす必要がないので、しばらく時間を節約するためにexample of visitor pattern in swift by Oktawian Chojnackiを使用します。

protocol PlanetVisitor { 
    func visit(planet: PlanetAlderaan) 
    func visit(planet: PlanetCoruscant) 
    func visit(planet: PlanetTatooine) 
} 

protocol Planet { 
    func accept(visitor: PlanetVisitor) 
} 

class PlanetAlderaan: Planet { 
    func accept(visitor: PlanetVisitor) { visitor.visit(self) } 
} 
class PlanetCoruscant: Planet { 
    func accept(visitor: PlanetVisitor) { visitor.visit(self) } 
} 
class PlanetTatooine: Planet { 
    func accept(visitor: PlanetVisitor) { visitor.visit(self) } 
} 

class NameVisitor: PlanetVisitor { 
    var name = "" 

    func visit(planet: PlanetAlderaan) { name = "Alderaan" } 
    func visit(planet: PlanetCoruscant) { name = "Coruscant" } 
    func visit(planet: PlanetTatooine) { name = "Tatooine" } 
} 

私が解決しようとしている問題はPlanetから派生した各クラスの決まり文句を軽減することです。 ご覧のとおり、すべて同じ機能が複製されていますfunc accept(visitor: PlanetVisitor) { visitor.visit(self) }

Planetプロトコルのデフォルト実装を実装して、それを基本クラスに実装しようとしましたが、Swiftはコンパイル時のオーバーロードの問題でそれを許可していないようです。

例:プロトコル上

デフォルトの実装:

extension Planet { 
    func accept(visitor: PlanetVisitor) { visitor.visit(self) } 
} 

基本クラス:

class PlanetBase: Planet { 
    func accept(visitor: PlanetVisitor) { visitor.visit(self) } 
} 

class PlanetAlderaan: PlanetBase {} 
class PlanetCoruscant: PlanetBase {} 
class PlanetTatooine: PlanetBase {} 

accept機能は、一般的な作られたとに自動的に適用することができること方法のいずれかを知っていますPlanetから派生した具体的なクラスはどれですか?それは重大な問題ではありませんが、大きなパズルです!

答えて

1

短い回答:できません。これは設計によるものです。

あなたが安定した惑星数を持っているが、まだ訪問者の数が不明な場合のための訪問者パターン。したがって、訪問者の将来の拡張を計画し、この定型文を一度作成します。さらに多くの訪問者を追加することは、惑星を変更することなく可能です。

大きなプロジェクトでは、コード生成を行うことができます。推奨しない


、あなたの代わりには、惑星を直接スイッチ、不要定型コードです:あなたは簡単に惑星を忘れることができますので、これは、エラーが発生しやすい

func foo(planet: Planet) { 
    if planet is PlanetAlderaan { 
     name = "Alderaan" 
    } 
    else if planet is PlanetCoruscant { 
     name = "Coruscant" 
    } 
    else if planet is PlanetTatooine { 
     name = "Tatooine" 
    } 
} 

。 Visitorパターンは、すべてのケースのコードを記述しなければなりません。それ以外の場合はコンパイルされません。

enum Planet { 
    case alderaan 
    case coruscant 
    case tatooine 

    func accept(visitor: PlanetVisitor) { 
     visitor.visit(planet: self) 
    } 
} 

protocol PlanetVisitor { 
    func visit(planet: Planet) 
} 

class NameVisitor: PlanetVisitor { 
    var name = "" 

    func visit(planet: Planet) { 
     switch planet { 
     case .alderaan: 
      name = "Alderaan" 
     case .coruscant: 
      name = "Coruscant" 
     case .tatooine: 
      name = "Tatooine" 
     } 
    } 
} 

あなたはswitchdefaultを使用しない場合は、どのような場合であれば、コンパイラは文句を言わないコードがコンパイルさせていることが保証だ:

+0

あなたはそうです!何らかの理由で私はC++のような他の言語が基本クラスでacceptメソッドを実装できると考えましたが、間違っていました。参照:https://stackoverflow.com/questions/17190873/c-visitor-pattern-why-should-every-derived-visited-implement-accept –

0

読書は、私は忘却の場合の問題を回避しながら、あなたが定型を減らすことができるという考えを持って答える@paiv処理されません。

しかし、他の定型文がPlanetタイプに移行する可能性があります。

+1

Visitorパターンは、オブジェクト指向での列挙型コーディングを可能にするために部分的に発明されました言語。Swiftに大きなenumサポートがあることを考えると、Visitorパターンは冗長です。このコードを注意深く見れば、 'PlanetVisitor'クラスは' Planet' enumを直接取る関数に置き換えることができます。私はここで 'ビジター'パターンに何の利益も見ません。 – hashemi

関連する問題