2016-01-16 2 views
0

Я новичок в программировании в Swift, и я достиг блокатора при построении шаблона проектирования Factory. Ниже мой код:Swift: Factory Pattern, методы подкласса не видны

protocol IInterface { 
    func InterfaceMethod() -> Void 
} 

public class SubClass: IInterface { 
    init() {} 

    func InterfaceMethod() { } 

    public func SubClassMethod() { } 
} 

public class Factory() { 
    class func createFactory() -> IInterface { 
     return SubClass() 
    } 
} 

Наконец, я пытаюсь получить доступ к нему, как показано ниже

let mgr = Factory.createFactory() 

//calling Interface Method 
mgr.InterfaceMethod() -- This works, when i keep a dot (mgr.) it shows the method name 
//calling subclass method 
mgr.SubClassMethod() -- This doesn't work, when i keep a dot (mgr.) it doesnt even show the subclass method name 

Даже если я использую mgr.SubClassMethod, он выдает ошибку говоря

Value of type IInterface has no member SubClassMethod

Я считаю, что я получая только протокольные методы, хотя объект SubClass возвращается через завод

Все примеры, которые я просматривал и видел, показывают только, как использовать методы, указанные в протоколе, но я не видел примера, где он показывает, как использовать собственные методы подкласса, кроме методов протоколов.

ответ

5

Вы пропустите точку фабричной модели. Идея шаблона Factory заключается в предоставлении методов, которые имеют конкретные типы возвращаемого типа и возврата, которые либо имеют этот тип, либо наследуют от этого типа (если это тип class) или соответствуют этому типу (если это).

Клиентский код, вызывающий фабричный метод, не должен размышлять о его возвращаемом значении и попытаться его применить к конкретному классу. Это полностью разрушает точку использования шаблона Factory.

Как вы можете видеть в приведенном выше примере AnimalFactory.getAnimal() экземпляр возврата некоторого типа, который соответствует протоколу Animal. Код, вызывающий этот метод, не знает и не должен знать об определенном типе этого экземпляра.

Если код вызова метод Factory ожидает, что возвращение экземпляра имеет тип Dog или наследует от этого типа, то вы должны создать и использовать отдельные DogFactory:

class EvilDog: Dog { 
    override func voice() -> String { 
     return "bark-bark" 
    } 
} 

class DogFactory { 
    func getDog() -> Dog { 
     return EvilDog() 
    } 
} 

Вы можете иметь ситуацию, когда код клиента реализовать различное поведение в зависимости от реального тип экземпляра, возвращаемого фабричным методом. В этом случае AnimalFactory следует применять методы для предоставления экземпляров всех типов, которые будут использоваться в коде клиента:

class AnimalFactory { 
    func getDog() -> Dog { 
     return EvilDog() 
    } 

    func getCat() -> Cat { 
     return Cat() 
    } 
} 

func trainAnimal(iLikeDogs: Bool, animalFactory: AnimalFactory) { 
    if iLikeDogs { 
     let dog = animalFactory.getDog() 
     dog.voice() 
     dog.sit() // only dog can sit 
    } else { 
     let cat = animalFactory.getCat() 
     cat.voice() 
    } 
} 

На самом деле есть три модели - завод, Abstract Factory и метод Factory. Вы можете прочитать о различиях here.

+1

Основная проблема в этом ответе заключается в том, что собаки 'EvilDog' отвечают на' .sit() ', это не вероятное поведение. Возможно, добавьте свойство 'var obedient: Bool = true' в' Dog' и переверните на 'false' для' EvilDog', после чего изменив функцию '.sit()', чтобы вернуть логическое значение, являющееся этим свойством 'obedient'. Шутки в сторону, хорошая почта, +1! ;) – dfri

0

Ваш let mgr имеет тип IInterface, который действительно не имеет SubClassMethod.

Если вы знаете, что Factory.createFactory() возвращает SubClass вы можете бросить его SubClass подобное:

let mgr = Factory.createFactory() as! SubClass 

Тогда let mgr будет типа SubClass, и вы должны быть в состоянии назвать mgr.SubClassMethod.

Тем не менее, ваш пример не имеет ничего общего с шаблоном проектирования фабрики, хотя вы назвали класс Factory. Взгляните на комментарий @ mixel.

+0

Ваш ответ противоречит концепции Factory pattern. – mixel

+1

@mixel Вы правы, но OP не задавал вопрос явно, и мой ответ по крайней мере помогает составить его пример. Надеюсь, что добавленное объяснение делает его более ясным. – kostek

1

Протокол может быть соответствовали по нескольким лицам (в вашем случае, класс SubClass), но сам протокол не знает о том, какие объекты, которые, соответствующие к нему. Поскольку ваш метод createFactory() возвращает тип (протокол) IInterface, а не тип SubClass, возврат как есть не будет знать о членах, относящихся к SubClass, даже если в качестве возврата отправлен объект SubClass.

let mgr = Factory.createFactory() /* Type: let mgr: IInterface */ 

Это также очевидно при попытке вызова члена SubClassMethod (или любой неизвестный элемент, скажем .foo, для этого Metter) на экземпляре mgr

error: value of type 'IInterface' has no member 'SubClassMethod'

Чтобы обернуть его, тип, соответствующий протокол будет иметь доступ ко всем голубым методам и свойствам в этом протоколе, но экземпляр протокола, используемого в качестве типа (который является приемлемым, если у вас нет Я или каких-либо связанных типов в вашем протоколе) ничего не знает о методах и свойства других типов, которые соответствуют этому протоколу.


Как упомянуто ниже, если вы знаете возвращение типа IInterface имеет определенный тип, то вы можете попытаться преобразование типа (as?) к данному типу, например, ... as? SubClass.Однако обратите внимание, однако, что протокол IInterface не знает о том, какие типы, которые ему соответствуют, преобразованию этого типа нельзя утверждать как успешное во время компиляции; это строго что-то, что можно контролировать как разработчик, возможно, приводя к исключениям во время выполнения, если вы не будете осторожны (например, используя небезопасные методы, такие как принудительное преобразование as!). Теперь, если функция всегда возвращает SubClass типа, вы можете также изменить свою подпись

class func createFactory() -> SubClass { 

Как возможное использование при держа IInterface возвращение если createFactory() на самом деле возвращает различных типов, что все соответствуют к IInterface протокол. В этом случае можно смело использовать switch блок над createFactory() возвращения выполнить преобразование типа для Вас различных известных типов (известных разработчиком), которые соответствуют IInterface следующего

protocol IInterface { 
    func InterfaceMethod() -> Void 
} 

public class SubClass: IInterface { 
    init() {} 

    func InterfaceMethod() { } 

    public func SubClassMethod() { } 
} 

public class AnotherClass: IInterface { 
    init() {} 

    func InterfaceMethod() { } 

    public func AnotherClassMethod() { } 
} 

public class Factory { 
    class func createFactory() -> IInterface { 

     if arc4random_uniform(5) > 2 { 
      return SubClass() 
     } 
     else { 
      return AnotherClass() 
     } 
    } 
} 

switch блока над возвратом, когда вам звонит фабричный метод:

switch(Factory.createFactory()) { 
case let mgr as SubClass: 
    print("Subclass") 
    mgr.SubClassMethod() 
case let mgr as AnotherClass: 
    print("AnotherClass") 
    mgr.AnotherClassMethod() 
// default case 
case let mgr as IInterface: 
    print("Unknown specific regarding return type") 
} 

Наконец, возможно, ответ на следующий вопрос SO может иметь значение для вас