import Foundation import UIKit struct ViewStyle { let style: (T) -> Void } let filled = ViewStyle { $0.setTitleColor(.white, for: .normal) $0.backgroundColor = .red } let rounded = ViewStyle { $0.layer.cornerRadius = 4.0 } extension ViewStyle { func compose(with style: ViewStyle) -> ViewStyle { return ViewStyle { self.style($0) style.style($0) } } } let roundedAndFilled = rounded.compose(with: filled) extension ViewStyle where T: UIButton { static var filled: ViewStyle { return ViewStyle { $0.setTitleColor(.white, for: .normal) $0.backgroundColor = .red } } static var rounded: ViewStyle { return ViewStyle { $0.layer.cornerRadius = 4.0 } } static var roundedAndFilled: ViewStyle { return rounded.compose(with: filled) } } func style(_ object: T, with style: ViewStyle) { style.style(object) } protocol Stylable { init() } extension UIView: Stylable {} extension Stylable { init(style: ViewStyle) { self.init() apply(style) } func apply(_ style: ViewStyle) { style.style(self) } } let button = UIButton(style: .roundedAndFilled) button.setTitle("My Button", for: .normal) button.sizeToFit() button