2016-11-23 19 views
5

Tôi đang triển khai mẫu khách truy cập trong Swift 2.2 cho một dự án tại nơi làm việc.Làm thế nào tôi có thể giảm bớt bản mẫu với mẫu khách truy cập trong Swift?

Vì vậy mà tôi không phải đun sôi mã nguồn của mình và để tiết kiệm cho tôi một thời gian, tôi sẽ sử dụng 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" } 
} 

Vấn đề tôi đang cố gắng giải quyết là giảm bớt bản mẫu trên mỗi lớp có nguồn gốc từ Planet. Như bạn có thể thấy tất cả chúng đều có cùng chức năng được sao chép func accept(visitor: PlanetVisitor) { visitor.visit(self) }.

Tôi đã thử cài đặt mặc định trên giao thức Planet và triển khai nó trên lớp cơ sở và Swift dường như không cho phép điều đó do giải quyết quá tải thời gian biên dịch.

Ví dụ:

Mặc định thực hiện trên giao thức:

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

Base Class:

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

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

Có ai biết một cách rằng accept chức năng có thể được thực hiện chung chung và áp dụng tự động để mỗi lớp bê tông có nguồn gốc từ Planet? Nó không phải là một vấn đề quan trọng nhưng nó là một câu đố tuyệt vời!

Trả lời

1

Câu trả lời ngắn: không thể, và điều này là do thiết kế.

Mẫu khách truy cập dành cho trường hợp khi bạn có số lượng hành tinh ổn định, nhưng số lượng khách truy cập chưa biết. Vì vậy, bạn lên kế hoạch cho các tiện ích mở rộng trong tương lai ở khách truy cập, viết bản mẫu này một lần. Thêm nhiều khách truy cập hơn sau đó có thể không có thay đổi đối với các hành tinh.

Trong một dự án lớn, bạn có thể sử dụng tạo mã.


Không được đề xuất, thay thế của bạn là một chuyển đổi trực tiếp trên hành tinh, không có mã boilerplate cần thiết:

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

Đây là dễ bị lỗi, vì bạn có thể dễ dàng quên hành tinh. Mô hình khách truy cập buộc bạn viết mã cho tất cả các trường hợp, nếu không nó sẽ không biên dịch.

+0

Bạn nói đúng! Đối với một số lý do tôi nghĩ rằng các ngôn ngữ khác như C + + có thể thực hiện phương pháp chấp nhận trong một lớp cơ sở nhưng nó quay ra tôi đã sai. Xem: https://stackoverflow.com/questions/17190873/c-visitor-pattern-why-should-every-derived-visited-implement-accept –

0

Reading @paiv trả lời tôi đã nhận ý kiến ​​cho rằng bạn có thể giảm soạn sẵn trong khi tránh vấn đề trường hợp lãng quên:

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

Nếu bạn sẽ không sử dụng default trong switch nó đảm bảo rằng trình biên dịch sẽ không cho phép mã biên dịch nếu có trường hợp là không được xử lý.

Nhưng tôi nghĩ một số bản mẫu khác có thể di chuyển bên trong loại Planet.

+1

Mẫu khách truy cập được phát minh một phần để cho phép mã hóa kiểu enum trong hướng đối tượng ngôn ngữ.Cho rằng Swift có hỗ trợ enum tuyệt vời, mô hình Visitor là thừa. Nếu bạn xem xét cẩn thận mã này, bất kỳ lớp 'PlanetVisitor' nào cũng có thể được thay thế bằng một hàm lấy trực tiếp' Planet' enum. Tôi không thấy bất kỳ lợi ích nào cho mẫu khách truy cập ở đây. – hashemi

Các vấn đề liên quan