Quick program for the interface

the Car and Truck classes are written here as an example, but they may not be known to the program at compile time.

there may be even more unknown cars

for example, there may be a special class of Ferrari, Lamborghini, that can go down a road unknown to the system.

Our goal is to program an interface, not a specific implementation

we need to do similarly to the following

  • create an instance var vehicle: IDrive = Vehicle()

  • vehicle.drive()

we tried some methods and couldn't get it to work without dropping specific implementations, need an independent solution without having to cast to a specific implementation.

Any lateral approach is also welcome , perhaps our approach is completely wrong, but given the limitations that a function instantiateAndDrive

must have a parameterprotocol

A note to negative voters aka dummies: ask questions instead to clarify if this makes sense for you or go for a "Design Pattern Book for Idiots"

    public protocol IDrive {
        func drive()
    }

    public class Car: IDrive {
        public init() {}
        public func drive() {}
    }

    class Truck: IDrive {
        public init() {}
        public func drive() {}
    }

class Test { //our attempts
   func instantiateAndDrive(Vehicle:IDrive.Type) {
       var vehicle = Vehicle()
       vehicle.drive()

   }

    func instantiateAndDrive2<T:IDrive>(Vehicle: T) {
        var vehicle = Vehicle()
        vehicle.drive()
    }
}

var test = Test()
test.instantiateAndDrive(Car.self)

      

Edit - Trying to use the class after AirSpeed ​​speed response

public protocol Drivable {
    init()
    func drive()
}

public class Car: Drivable {
    public required init() {}
    public func drive() { println("vroom") }
}

public class Truck: Drivable {
    public required init() {}

    public func drive() { println("brrrrrrm") }
}

class Test {
    func instantiateAndDrive(Vehicle:Drivable.Type) {
        var vehicle = Vehicle()
        vehicle.drive()
    }

    func instantiateAndDrive2<T:Drivable>(Vehicle: T) {
        ver vehicle = Vehicle()
        vehicle.drive()
    }
}
//var test = Test()
//test.instantiateAndDrive(Car.self)
//test.instantiateAndDrive(Truck.self)

      

0


source to share


2 answers


To create a generic type in general, you need to know that it supports an initializer. You can do this by adding a function to the protocol init()

:

public protocol Drivable {
    // enable drivable things to be
    // created with a  default initializer
    init()

    // (you could instead require a type implement
    // an initializer that took parameters)

    func drive()
}

      

Then you can write functions that create and work with them in general:

struct Car: Drivable {
    init() { }
    func drive() { println("vroom") }
}

struct Truck: Drivable {
    init() { }
    func drive() { println("brrrrrrm") }
}

struct Test<D: Drivable> {
    func instantiateAndDrive() {
        // whatever D is, it implements init()
        let d = D()
        // and drive()
        d.drive()
    }
}

Test<Car>().instantiateAndDrive()
Test<Truck>().instantiateAndDrive()

      



Although with this approach, when you say "the Car and Truck classes are written here as examples, but they may not be known to the program at compile time" - the above code means that they do not need to know about the implementation of the Test at compile time. But they must be known to the calling test at compile time.

This approach is more useful when genric returns a type. For example, it ExtensibleCollectionType

requires init()

and therefore can be used as follows:

func returnCollectionContainingOne<C: ExtensibleCollectionType where C.Generator.Element == Int>() -> C {

    // this is allowed because the ExtensibleCollectionType procol 
    // requires the type implement an init() that takes no parameters
    var result = C()

    // and it also defines an `append` function that allows you to do this:
    result.append(1)

    // note, the reason it was possible to give a "1" as the argument to
    // append was because of the "where C.Generator.Element == Int" part
    // of the generic placeholder constraint 

    return result
}

// now you can use returnCollectionContainingOne with arrays:
let a: [Int] = returnCollectionContainingOne()

// or with ContiguousArrays:
let b: ContiguousArray = returnCollectionContainingOne()

      

+2


source


You want to use Self

. In the protocol, it means "the type that actually accepts me." In a class method, it means "the class in which this method is actually called".



+1


source







All Articles