class Animals{
var name : String = "default"
var age : Int = 0
func Details()-> String{
return "This animal is a \(name) and has \(age) years old."
}
}
class Dogs : Animals{
name = "dog"
}
class Cats : Animals{
name = "cat"
}
var MyAnimal = Dogs()
我希望看到这样的信息:"这只动物是一只狗,已经0岁了。" 但每次我收到这个:"这只动物是默认的,已经0岁了。"
var HisAnimal = Cats()
答案 0 :(得分:2)
如果您想要存储而非计算的属性,可以在初始值设定项中设置name
,如下所示:
class Animal {
let name: String
var age: Int = 0
/* designated initializer: fully initializes all instance properties */
init(name: String) {
self.name = name
}
func details() -> String {
return "This animal is a \(name) and has \(age) years old."
}
}
class Dog : Animal {
/* designated initializer of subclass: must call a designated
initializer from its immediate superclass */
init() {
super.init(name: "dog")
}
}
class Cat : Animal {
/* ... */
init() {
super.init(name: "cat")
}
}
let myAnimal = Dog()
此机制确保name
仅从一个位置设置,并显式传递给初始化程序。
答案 1 :(得分:1)
您很可能会创建Cat
:s和Dog
:s的实例,但您可能不希望为抽象的奇怪Animal
:s创建实例。 Animal
作为常见超类的替代方法是让它成为协议。
protocol Animal {
static var species: String { get }
var name: String? { get }
var age: Int { get set }
var details: String { get }
}
extension Animal {
static var species: String { return "\(self)".lowercased() }
// since all the properties used in 'details' are blueprinted,
// we might as well supply a default implementation of it.
var details: String {
return "This animal is a \(Self.species)\(name.map{ " named \($0)" } ?? ""), aged \(age)."
}
}
struct Dog: Animal {
let name: String?
var age: Int
init(age: Int, name: String? = nil) {
self.name = name
self.age = age
}
}
var myDog = Dog(age: 3, name: "Fred")
print(myDog.details) // This animal is a dog named Fred, aged 3.
myDog.age = 4 // grats to Fred!
print(myDog.details) // This animal is a dog named Fred, aged 4.
let wildDog = Dog(age: 6) // never named ...
print(wildDog.details) // This animal is a dog, aged 3.
请注意,我选择使用类属性species
来命名每只动物的种类,并为那些被赋予名称的动物保留实例属性name
;比如,你的亲爱的狗名为Fred
(而不是你亲爱的狗dog
)。
使用协议也可以自然地选择泛型而不是类型化的抽象类型(后者在使用公共超类时可能很诱人):
struct Cat: Animal {
let name: String?
var age: Int
init(age: Int, name: String? = nil) {
self.name = name
self.age = age
}
}
var wildCat = Cat(age: 2)
func yieldBirthday<T: Animal>(for animal: inout T) {
print(animal.details)
animal.age += 1
print("This \(T.species) now had a birthday!")
print(animal.details)
}
yieldBirthday(for: &myDog)
/* This animal is a dog named Fred, aged 4.
This dog now had a birthday!
This animal is a dog named Fred, aged 5. */
yieldBirthday(for: &wildCat)
/* This animal is a cat, aged 2.
This cat now had a birthday!
This animal is a cat, aged 3. */
答案 2 :(得分:0)
解决的一种方法是使用&#34;模板方法模式&#34;
class Animals {
lazy var name : String = self.defaultName
var defaultName:String { return "default" }
func Details()-> String{
return "This animal is a \(name) and has \(age) years old."
}
}
class Dogs : Animals {
override var defaultName:String { return "dog" }
}
另一种方法是为每个子类创建init
方法并覆盖默认值
答案 3 :(得分:0)
通过创建初始化程序来设置名称(使用默认值),我将通过以下方式执行此操作:
class Animal: CustomStringConvertible {
let name: String
let age: Int
init(name: String = "default", age: Int = 0) { // FIXME: Does a default age of 0 make sense?
self.name = name
self.age = age
}
public var description: String {
return "This animal is a \(name) and is \(age) years old."
}
}
class Dog: Animal {
init() {
super.init(name: "Dog")
}
}
class Cat: Animal {
init() {
super.init(name: "Cat")
}
}
var myAnimal = Dog()
print (myAnimal)