我正在尝试制作一个服装推荐应用程序,但遇到了问题。我有一个名为衣柜的属性,我想在其中存储与用户选择的活动类型相关的所有衣物。
我的方法如下:
func recommendClothing(for conditions: WeatherForSelection, type: ActivityType){
temperature = conditions.feelsLike ?? 0
isWindy = conditions.windSpeed ?? 0 > 5
let wardrobe = CyclingClothing.self
clothing = [
Clothing(title: "Head", description: wardrobe.Head.forTemperature(temperature).name, image: wardrobe.Head.forTemperature(temperature).image),
Clothing(title: "Base Layer", description: wardrobe.BaseLayer.forTemperature(temperature).name, image: wardrobe.BaseLayer.forTemperature(temperature).image),
Clothing(title: "Mid Layer", description: wardrobe.MidLayer.forTemperature(temperature).name, image: wardrobe.MidLayer.forTemperature(temperature).image),
Clothing(title: "Legs", description: wardrobe.Legs.forTemperature(temperature).name, image: wardrobe.Legs.forTemperature(temperature).image),
Clothing(title: "Hands", description: wardrobe.Hands.forTemperature(temperature).name, image: wardrobe.Hands.forTemperature(temperature).image),
Clothing(title: "Feet", description: wardrobe.Feet.forTemperature(temperature).name, image: wardrobe.Feet.forTemperature(temperature).image)
]
if wardrobe.Shell.forTemperature(temperature) != .none {
clothing.append(Clothing(title: "Shell", description: wardrobe.Shell.forTemperature(temperature).name, image: wardrobe.Shell.forTemperature(temperature).image))
}
if isWindy {
clothing.append(Clothing(title: "Wind Protection", description: "Windproof Layer", image: "windproof"))
}
if conditions.isRaining ?? false {
clothing.append(Clothing(title: "Rain Protection", description: "Waterproof Layer", image: "raincoat"))
}
}
我想,我只需打开输入type并根据它选择衣柜即可。但接下来我必须定义衣柜的类型,它总是不同的。所以我尝试将 Clothing 结构放入一个名为 Wardrobe 的主结构中,并仅选择衣柜的子结构,但这对我来说也不起作用......我也尝试了一些协议和扩展的恶作剧,但自从我'我对此还很陌生,它也不起作用......
类可以继承工作吗?
有没有办法让它工作或者我必须一起改变逻辑?
服装结构示例如下所示:
struct CyclingClothing {
//MARK: - Head
enum Head {
case helmet, headBand, lightCap, winterCap
static func forTemperature(_ temperature: Double) -> Head {
switch temperature {
case ..<5:
.winterCap
case 5..<10:
.lightCap
case 10..<15:
.headBand
case 15..<30:
.helmet
default:
.helmet
}
}
var name: String {
switch self {
case .helmet:
"Just a Helmet"
case .headBand:
"Headband"
case .lightCap:
"Skullcap"
case .winterCap:
"Winter Cap"
}
}
var image: String {
switch self {
case .helmet:
"helmet"
case .headBand:
"headband"
case .lightCap:
"light_cap"
case .winterCap:
"winter_cap"
}
}
}
//MARK: - Base Layer
enum BaseLayer {
case none, lightBase, thermalBase
static func forTemperature(_ temperature: Double) -> BaseLayer {
switch temperature {
case ..<10:
.thermalBase
case 10..<20:
.lightBase
default:
.none
}
}
var name: String {
switch self {
case .none:
"No Base Layer"
case .lightBase:
"Light"
case .thermalBase:
"Thermal"
}
}
var image: String {
switch self {
case .none:
"body"
case .lightBase:
"light_base"
case .thermalBase:
"thermal_base"
}
}
}
//MARK: - Mid Layer
enum MidLayer {
case jersey, longJersey, thermalJersey
static func forTemperature(_ temperature: Double) -> MidLayer {
switch temperature {
case ..<10:
.thermalJersey
case 10..<20:
.longJersey
default:
.jersey
}
}
var name: String {
switch self {
case .jersey:
"Jersey"
case .longJersey:
"Long Sleeved Jersey"
case .thermalJersey:
"Thermal Jersey"
}
}
var image: String{
switch self {
case .jersey:
"jersey"
case .longJersey:
"long_jersey"
case .thermalJersey:
"thermal_jersey"
}
}
}
//MARK: - Shell
enum Shell {
case none, lightJacket, insulatedJacket
static func forTemperature(_ temperature: Double) -> Shell {
switch temperature {
case ..<5:
.insulatedJacket
case 5..<15:
.lightJacket
default:
.none
}
}
var name: String {
switch self {
case .none:
"No Shell"
case .lightJacket:
"Light Jacket"
case .insulatedJacket:
"Insulated Jacket"
}
}
var image: String {
switch self {
case .none:
"no_shell"
case .lightJacket:
"light_jacket"
case .insulatedJacket:
"insulated_jacket"
}
}
}
//MARK: - Legs
enum Legs {
case shorts, longBibs, thermalBibs
static func forTemperature(_ temperature: Double) -> Legs {
switch temperature {
case ..<10:
.thermalBibs
case 10..<18:
.longBibs
default:
.shorts
}
}
var name: String {
switch self {
case .shorts:
"Bib Shorts"
case .longBibs:
"Long Bibs"
case .thermalBibs:
"Thermal Bibs"
}
}
var image: String {
switch self {
case .shorts:
"bib_shorts"
case .longBibs:
"long_bibs"
case .thermalBibs:
"thermal_bibs"
}
}
}
//MARK: - Hands
enum Hands {
case longGloves, insulatedGloves, summerGloves
static func forTemperature(_ temperature: Double) -> Hands {
switch temperature {
case ..<10:
.insulatedGloves
case 10..<15:
.longGloves
default:
.summerGloves
}
}
var name: String {
switch self {
case .summerGloves:
"Summer Gloves"
case .longGloves:
"Long Gloves"
case .insulatedGloves:
"Insulated Gloves"
}
}
var image: String {
switch self {
case .summerGloves:
"gloves"
case .longGloves:
"long_gloves"
case .insulatedGloves:
"insulated_gloves"
}
}
}
//MARK: - Feet
enum Feet {
case summerSocks, warmSocks, shoeCovers, winterShoes
static func forTemperature(_ temperature: Double) -> Feet {
switch temperature {
case ..<3:
return .winterShoes
case 3..<7:
return .shoeCovers
case 7..<15:
return .warmSocks
default:
return .summerSocks
}
}
var name: String {
switch self {
case .summerSocks:
"Light Socks"
case .warmSocks:
"Warm Socks"
case .shoeCovers:
"Shoe Covers"
case .winterShoes:
"Winter Shoes"
}
}
var image: String {
switch self {
case .summerSocks:
"socks"
case .warmSocks:
"warm_socks"
case .shoeCovers:
"covers"
case .winterShoes:
"winter_shoes"
}
}
}
}
您的代码中可能还有其他问题,但要修复
wardrobe
,我建议您将 CyclingClothing
从 struct
更改为 enum
。
然后从函数中删除
wardrobe
常量,并将其所有使用替换为 CyclingClothing
比如说
Clothing(title: "Head",
description: CyclingClothing.Head.forTemperature(temperature).name,
image: CyclingClothing.Head.forTemperature(temperature).image)
您的代码使用类型作为值,这种方式使用起来非常棘手。
您将遇到的第一个问题是您无法有条件地选择
wardrobe
值来选择两种类型中的一种。例如。这行不通:
let wardrobe = cycling ? CyclingWardrobe.self : WalkingWardrobe.self
因为
CyclingWardrobe
和WalkingWardrobe
是两种完全不相关的类型。它们可能在结构上恰好相似,但这无关紧要。这类似于拥有let i = small ? Int8() : Int64()
。
为了使它们像这样具有互操作性,您需要引入一个抽象(超类或协议),将它们聚集在一个公共类型下,该类型表示它们都可以处理的操作。但在这种情况下,您可以按名称访问嵌套类型,并且没有(简单)方法对其进行抽象。这一切很快就会变得一团糟。
相反,您应该直接使用对象/值。无需在类型级别进行“元”。
head
、baseLayer
、midLayer
等提供某些东西的能力。将它们捕获为
协议的要求(函数或变量)。Wardrobe
协议的不同类型,以独特的方式实现这些要求。这是一个入门示例:
struct Clothing {
let title: String
let description: String
let image: String
}
struct WeatherConditions {
let temperature: Double
let isWindy: Bool
let isRaining: Bool
}
enum ActivityType {
case cycling
case walking
}
// A Wardrobe is a thing that can provide you with a particular kind of clothing
protocol Wardrobe {
// TODO: should these be optional?
// E.g. imagine if there was `ActivityType.beachParty`
var head: Clothing { get }
var baseLayer: Clothing { get }
var midLayer: Clothing { get }
var legs: Clothing { get }
var hands: Clothing { get }
var feet: Clothing { get }
// Add a way for wardrobes to add other stuff, if necessary.
var other: [Clothing] { get }
}
extension Wardrobe {
func recommendClothing() -> [Clothing] {
return [head, baseLayer, midLayer, legs, hands, feet] + other
}
}
func chooseWardrobe(activity: ActivityType, conditions: WeatherConditions) -> any Wardrobe {
switch activity {
case .cycling:
return CyclingWardrobe(forConditions: conditions)
case .walking:
// Example TODO: Create a WalkingWardrobe that conforms to Wardrobe
fatalError("Implement me!")
}
}
struct CyclingWardrobe: Wardrobe {
let weatherConditions: WeatherConditions
public init(forConditions weatherConditions: WeatherConditions) {
self.weatherConditions = weatherConditions
}
private var temperature: Double { return weatherConditions.temperature }
var head: Clothing {
switch temperature {
case ..<5: return Clothing(title: "Head", description: "Winter Cap", image: "winter_cap")
case 5..<10: return Clothing(title: "Head", description: "Skullcap", image: "light_cap" )
case 10..<15: return Clothing(title: "Head", description: "Headband", image: "headband" )
default: return Clothing(title: "Head", description: "Just a Helmet", image: "helmet" )
}
}
var baseLayer: Clothing {
switch temperature {
case ..<10: return Clothing(title: "Base Layer", description: "Thermal", image: "thermal_base")
case 10..<20: return Clothing(title: "Base Layer", description: "Light", image: "light_base" )
default: return Clothing(title: "Base Layer", description: "No Base Layer", image: "body" )
}
}
var midLayer: Clothing {
switch temperature {
case ..<10: return Clothing(title: "Mid layer", description: "Thermal Jersey", image: "thermal_jersey")
case 10..<20: return Clothing(title: "Mid layer", description: "Long Sleeved Jersey", image: "long_jersey")
default: return Clothing(title: "Mid layer", description: "Jersey", image: "jersey")
}
}
var legs: Clothing {
switch temperature {
case ..<10: return Clothing(title: "Legs", description: "Thermal Bibs", image: "thermal_bibs")
case 10..<18: return Clothing(title: "Legs", description: "Long Bibs", image: "long_bibs" )
default: return Clothing(title: "Legs", description: "Bib Shorts", image: "bib_shorts" )
}
}
var hands: Clothing {
switch temperature {
case ..<10: return Clothing(title: "Hands", description: "Insulated Gloves", image: "insulated_gloves")
case 10..<15: return Clothing(title: "Hands", description: "Long Gloves", image: "long_gloves" )
default: return Clothing(title: "Hands", description: "Summer Gloves", image: "gloves" )
}
}
var feet: Clothing {
switch temperature {
case ..<3: return Clothing(title: "Feet", description: "Winter Shoes", image: "winter_shoes")
case 3..<7: return Clothing(title: "Feet", description: "Shoe Covers" , image: "covers" )
case 7..<15: return Clothing(title: "Feet", description: "Warm Socks Covers", image: "warm_socks" )
default: return Clothing(title: "Feet", description: "Light Socks", image: "socks" )
}
}
var shell: Clothing? {
switch temperature {
case ..<5: return Clothing(title: "Mid Layer", description: "Insulated Jacket", image: "insulated_jacket")
case 5..<15: return Clothing(title: "Mid Layer", description: "Light Jacket", image: "light_jacket" )
default: return nil
}
}
var other: [Clothing] {
var clothing = [Clothing]()
if let shell = self.shell {
clothing.append(shell)
}
if weatherConditions.isWindy {
clothing.append(Clothing(title: "Wind Protection", description: "Windproof Layer", image: "windproof"))
}
if weatherConditions.isRaining {
clothing.append(Clothing(title: "Rain Protection", description: "Waterproof Layer", image: "raincoat"))
}
return clothing
}
}
您的来电者变得非常简单。它会咨询挑选器来为活动选择正确的衣柜,然后向衣柜询问所有推荐的衣服。勒芬。
let weather = WeatherConditions(temperature: 10, isWindy: false, isRaining: false)
let clothing = chooseWardrobe(activity: .cycling, conditions: weather).recommendClothing()
for article in clothing {
print("\(article.title): \(article.description)")
}