什么是构建都模式
将一个复杂对象的创建和表示进行分离,根据创建顺序不一样,表示的方式也不一样。如买手机时选择配置:iPhote7、玫瑰金、64g,你可以选择不同配置,但你却不知道他是如果实现的,同时也因为的选择配置的不同,生产的工艺和手机样式也不一样。用户不需要知道如何实现的,只选择最终的表示,这就是现实生活中构建者模式。
标准组成
- 抽象构建器(Builder):为构建器提供接口(iOS 中的协议)
- 具体构建器(ConcreteBuilder):构建具体的产品(实现 Builder 协议)
- 指挥者(Director):调用Builder接口來创建产品对象(这个不一定需要,可有可无)
- 产品角色(Product):具体的产品
结构
图上的指挥者(组装器)是不一定需要的,因为我们可以直接 iPhoneBuilder 来组装产品,而不需要再单独封闭一个类来实现,但要与不要,还是需要根据业务场景来确定,设计模式是死的,人是活的,至于怎么使用,还是那句话:按实际需求。
实现
这里实现一个日期的构建者:
// let bulider = DateBulider()
// bulider.setYear(2017).setMonth(5).setDay(25).setHour(11).setMinute(41).showDate()
class DateBulider: NSObject {
private var component: NSDateComponents?
override init() {
component = NSDateComponents()
// default
component?.calendar = Calendar(identifier: .gregorian)
}
func date() -> Date {
return (component?.date)!
}
func showDate() {
let formatter = DateFormatter()
formatter.dateFormat = "yy-MM-dd hh:mm:ss"
print(formatter.string(from: (component?.date)!))
}
func setCalender(identifier: Calendar.Identifier) -> DateBulider {
component?.calendar = Calendar(identifier: identifier)
return self
}
func setSecond(_ second: Int) -> DateBulider {
component?.second = second
return self
}
func setMinute(_ minute: Int) -> DateBulider {
component?.minute = minute
return self
}
func setHour(_ hour: Int) -> DateBulider {
component?.hour = hour
return self
}
func setDay(_ day: Int) -> DateBulider {
component?.day = day
return self
}
func setMonth(_ month: Int) -> DateBulider {
component?.month = month
return self
}
func setYear(_ year: Int) -> DateBulider {
component?.year = year
return self
}
}
上例的构建者,非严格标准的构建者,下面按标准来做,实现抽象构建器(DateBuilder Protocole):
protocol DateBuliderProtocole: class {
func date() -> Date
func showDate()
func setCalender(identifier: Calendar.Identifier) -> DateBulider
func setSecond(_ second: Int) -> DateBulider
func setMinute(_ minute: Int) -> DateBulider
func setHour(_ hour: Int) -> DateBulider
func setDay(_ day: Int) -> DateBulider
func setMonth(_ month: Int) -> DateBulider
func setYear(_ year: Int) -> DateBulider
}
并在 DateBulider 实现该 Protocole:
class DateBulider: DateBuliderProtocole {...}
到这里,这个例子可以说是比较标准的简单的构建者模式,Director 和 Product 并没有出现,但 Director 是不一定需要的,Product 部分也可以说是:
let bulider = DateBulider()
bulider.setYear(2017).setMonth(5).setDay(25).setHour(11).setMinute(41).showDate()
但这里没有封装成一个 Product 类,如果在复杂的场景下,Product 类还是需要有的。
非标准构建者模式
设计模式是一种思想,不是一成不变的,就构建者模式来说,实际中使用构建者模式很多者是标准模式的中变形,不过思想都是一样的,万变不离其宗。
下面了解下 Realm 中使用到的构建者模式,关于 Realm 的介绍就不多说了,一句话:
第一个专门针对移动平台设计的数据库,目标是取代SQLite。
Realm 中的数据库操作就是使用构建者模式,如:
// 添加/更新
realm.add(model, update: true)
// 删除
realm.delete(model)
// 查询条件
realm.objects(YHFeedItemModel.self).filter("isDel = false").filter("isFavorite = true")
这里就是构建者模式的一种应用,将一个复杂对象的创建和表示进行分离。如添加功能中,我们输入正确的实例就可以完成保存,但底层他到底是怎么实现的我们并不知道,而且我们也不关心。我们可以下载 Realm 的源码来看下的实现(大概知道流程就可以了,有兴趣的可以单独去下完整的源码看):
// Swift
public func add(_ object: Object, update: Bool = false) {
if update && object.objectSchema.primaryKeyProperty == nil {
throwRealmException("'\(object.objectSchema.className)' does not have a primary key and can not be updated")
}
RLMAddObjectToRealm(object, rlmRealm, update)
}
// OC
void RLMAddObjectToRealm(__unsafe_unretained RLMObjectBase *const object,
__unsafe_unretained RLMRealm *const realm,
bool createOrUpdate) {
RLMVerifyInWriteTransaction(realm);
// verify that object is unmanaged
if (object.invalidated) {
@throw RLMException(@"Adding a deleted or invalidated object to a Realm is not permitted");
}
if (object->_realm) {
if (object->_realm == realm) {
// Adding an object to the Realm it's already manged by is a no-op
return;
}
// for differing realms users must explicitly create the object in the second realm
@throw RLMException(@"Object is already managed by another Realm. Use create instead to copy it into this Realm.");
}
if (object->_observationInfo && object->_observationInfo->hasObservers()) {
@throw RLMException(@"Cannot add an object with observers to a Realm");
}
auto& info = realm->_info[object->_objectSchema.className];
RLMAccessorContext c{realm, info, true};
object->_info = &info;
object->_realm = realm;
object->_objectSchema = info.rlmObjectSchema;
try {
realm::Object::create(c, realm->_realm, *info.objectSchema, (id)object,
createOrUpdate, &object->_row);
}
catch (std::exception const& e) {
@throw RLMException(e);
}
object_setClass(object, info.rlmObjectSchema.accessorClass);
RLMInitializeSwiftAccessorGenerics(object);
}
这里就不详细读 Realm 的源码了,大概了解它的实现就可以了,主要是理解构建者模式的思想,关于构建者模式的内容就说到这里了,有空闲时候话,再简单写一个复杂一点 Demo 来补充说明了。
Demo可以从这里下载
-------------一般般的分割线 17.07.23 更新-------------
通过构建者实现自定义 UIAlertView
在最近开发中,需要实现一个支持添加图片的 AlertView,顺便也实践下构建者模块,直接上代码:
class JCAlertView: NSObject {
private var alertView: UIAlertView!
private override init() {}
static func bulid() -> JCAlertView {
let alertView = UIAlertView()
let alert = JCAlertView()
alert.alertView = alertView
return alert
}
public func setDelegate(_ delegate: AnyObject?) -> JCAlertView {
alertView.delegate = delegate
return self
}
public func setTitle(_ title: String) -> JCAlertView {
alertView.title = title
return self
}
public func setMessage(_ message: String) -> JCAlertView {
alertView.message = message
return self
}
public func setTag(_ tag: Int) -> JCAlertView {
alertView.tag = tag
return self
}
public func addButton(_ buttonTitle: String) -> JCAlertView {
alertView.addButton(withTitle: buttonTitle)
return self
}
public func addCancelButton(_ buttonTitle: String) -> JCAlertView {
alertView.addButton(withTitle: buttonTitle)
let count = alertView.numberOfButtons
alertView.cancelButtonIndex = count - 1
return self
}
public func addImage(_ image: UIImage) -> JCAlertView {
let imageView = UIImageView()
let scale = 270 / image.size.width
imageView.image = image.resizeImage(image: image, newSize: CGSize(width: image.size.width * scale, height: image.size.height * scale))
alertView.setValue(imageView, forKey: "accessoryView")
return self
}
public func show() {
alertView.show()
}
}