-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Attribute の最適化 #35
Comments
上記は生成部分のみでした。モディファイア部分も書いておきます。 public extension Attribute {
func fontName(_ value: String) -> Attribute {
var newContext = self.context
newContext.fontName = value
return .init(context: newContext)
}
func fontSize(_ value: NSNumber) -> Attribute {
var newContext = self.context
newContext.fontSize = value
return .init(context: newContext)
}
func foregroundColor(_ value: Scope.ForegroundColorAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.foregroundColor = value
return .init(context: newContext)
}
func backgroundColor(_ value: Scope.BackgroundColorAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.backgroundColor = value
return .init(context: newContext)
}
func kern(_ value: Scope.KernAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.kern = value
return .init(context: newContext)
}
func tracking(_ value: Scope.TrackingAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.tracking = value
return .init(context: newContext)
}
func baselineOffset(_ value: Scope.BaselineOffsetAttribute.Value) -> Attribute {
var newContext = self.context
newContext.container.baselineOffset = value
return .init(context: newContext)
}
} |
#34 を達成する場合は以下のような protocol を使用するといいかもしれません。 public protocol AttributeModifier {
func modify(context: inout AttributeContext)
}
extension Attribute {
func modified<Mod: AttributeModifier>(_ mod: Mod) -> Attribute {
var newContext = self.context
mod.modify(&newContext)
.init(context: newContext)
}
} 例: fontName struct FontName: AttributeModifier {
let value: String
func modify(context: inout AttributeContext) {
context.fontName = self.value
}
}
public extension Attribute {
func fontName(_ value: String) -> Attribute {
self.modified(FontName(value))
}
} |
もしこれがうまく機能する場合、enum を使う API と比較して以下のようなメリットがあると思われます。
|
Attribute を融合(merge)するのが難しいのでは? |
この方式では、Attribute を merge することが難しいです。なぜなら、style 設計者がどのプロパティを優先したいかが分からなくなってしまうからです。しかし、方法がないわけではありません。 まず各プロパティに対応する enum を作成します(自動で enum ModifiedProperty {
case fontName
case fontSize
case ...
} そして、子に列挙体の Set を用意しておきます。 let modifiedPropertyHistory: Set<ModifiedProperty> あとは Attribute に builder で情報を付加するたびに、プロパティに対応する case をこの Set に挿入していくだけです。 struct Attribute {
enum ModifiedProperty {
case fontName
case fontSize
case ...
}
let context: AttributeContext
let modifiedPropertyHistory: Set<ModifiedProperty>
} この手法のメリット・デメリットをメモしておきます。
|
ひとつ前のコメントのコードを実装するなら、というメモです。 public protocol AttributeModifier {
var propertyData: Attribute.ModifiedProperty { get }
func modify(context: inout AttributeContext)
}
extension Attribute {
func modified<Mod: AttributeModifier>(_ mod: Mod) -> Attribute {
var newContext = self.context
var newHistory = self.modifiedPropertyHistory
mod.modify(&newContext)
newHistory.insert(mod.propertyData)
return Attribute(context: newContext, modifiedPropertyHistory: newHistory)
}
} Attribute context の merge についてもメモしておきます。 extension AttributeContext {
// 他のコンテキストを、特定のプロパティについて変異させます
func modify(_ c: inout AttributeContext, forProperty property: Attribute.ModifiedProperty) {
switch property {
case .fontName:
c.fontName = self.fontName
case .fontSize:
c.fontSize = self.fontSize
case .foregroundColor:
c.container.foregroundColor = self.foregroundColor
// ...
default:
break
}
}
} |
Attribute をビルダーパターンで設計できるようにしていますが、AttributeContext を直接ビルドできるようにして仕舞えばいいでのはないか? という試みです。
不変性も維持したいのであればこんな感じでしょうか。
The text was updated successfully, but these errors were encountered: