工厂方法模式简介
工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。
工厂方法模式对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不再负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
工厂方法模式(Factory Method pattern)是最典型的模板方法模式(Template Method pattern)应用。
关于是什么的问题?
工厂方法模式通过选取相关的实现类来满足调用组件的请求,调用组件无需了解这些实现类的细节以及他们之前的关系。
有什么优点的问题?
工厂方法模式统一实现类的选取逻辑,避免了相关逻辑散布于整个程序的情况。也就是说,调用组件只依赖顶层协议或者基类,无需了解实现类及其选取的过程。
何时使用该模式?
当存在多个类共同实现一个协议
或者共同继承一个基类时
,就可以使用工厂模式。
何时应该避免使用该模式?
不存在共同协议或者没有共同基类时,则不应该使用此模式,因为此模式的运作机制要求调用组件只能依靠单一类型。
有哪些相关的模式?
工厂方法模式通常会与单例模式和对象池模式一起使用。
工厂方法模式的实际代码实现
工厂方法模式的实现通常可以是借助类的继承或者协议来实现。具体是用类的继承还是用协议来实现,都是无关紧要的,对整个设计模式而言并不会产生什么影响。所以完全可以依照个人的代码习惯来实现。
protocol DrawShape{
func draw()
}
//长方形
class Rectangle:DrawShape{
func draw() {
print("draw a rectangle!")
}
}
//圆形
class Circle:DrawShape{
func draw() {
print("draw a circle!")
}
}
//正方形
class Square:DrawShape{
func draw() {
print("draw a square!")
}
}
//图形类型
enum ShapeType{
case rectangle,circle,square
}
//绘制图形工厂
class ShapeFactory{
static func getShapeWithType(type: ShapeType) -> DrawShape?{
switch type {
case .rectangle:
return Rectangle()
case .circle:
return Circle()
case .square:
return Square()
default:
return nil
}
}
}
//获取对应类型的实例并执行绘制
let shape1 = ShapeFactory.getShapeWithType(type: ShapeType.rectangle)
shape1?.draw()
let shape2 = ShapeFactory.getShapeWithType(type: ShapeType.circle)
shape2?.draw()
let shape3 = ShapeFactory.getShapeWithType(type: ShapeType.square)
shape3?.draw()
/*
打印结果如下:
draw a rectangle!
draw a circle!
draw a square!
*/
抽象工厂模式简介
抽象工厂模式同前面所讲的工厂方法模式类似。不同的是,抽象工厂模式允许调用组件在不了解创建对象所需类的情况下,创建一组或一系列相关的对象。更直接的说:抽象工厂就是工厂的工厂
,目的是使工厂也能按需动态创建。
关于是什么的问题?
抽象工厂模式允许调用组件创建一组相关联的对象。调用组件无需了解创建对象所使用的类,以及选择这些类的理由。这个模式与前面所讲的工厂方法模式类似,不同的是此模式可以为调用组件提供一组对象。
有什么优点的问题?
抽象工厂模式允许调用组件不必了解创建对象使用的类,也不用知道选择这些类的原因。因此,我们可以在不修改调用组件的情况下,对其使用的类进行修改。
何时使用该模式?
关于何时使用此模式是一个重点,所以笔者一般会在这里着重标记一下。如果调用组件需要使用多个相互协作的对象,同时又无需了解这些对象之间的协作方式的时候
,就可以使用此模式。
何时应该避免使用该模式?
如果只是创建一个对象,就不应该使用此模式。此种场景下,应该使用相对简单的工厂方法模式。
有哪些常见的陷阱?
主要的陷阱是,将调用组件所使用的类的细节暴露给调用组件。比如调组件对选择实现类的决策过程存在依赖,或者对具体的某个类存在依赖。
抽象工厂模式的UML图
其中红色部分是客户端实际需接触的部分。
抽象工厂模式的UML图抽象工厂模式的实际代码实现
//产品相关
//产品一,phone
protocol Phone{
func call();//所有的手机都能打电话
}
class Samsung:Phone{
func call(){
print("Call from Samsung");
}
}
class IPhone:Phone{
func call(){
print("Call from iPhone")
}
}
//产品二,Usb
protocol USB{
func use();
}
class SamsungUSB:USB{
func use(){
print("USB for Samsung");
}
}
class IphoneUSB:USB{
func use(){
print("USB for IPhone");
}
}
//工厂相关
protocol PhoneRelatedFactory{
func createPhone()->Phone;
func createUSB()->USB;
}
//实际工厂一,负责生产三星的相关产品
class SamsungFactory:PhoneRelatedFactory{
func createPhone() -> Phone {
return Samsung()
}
func createUSB() -> USB {
return SamsungUSB()
}
}
class IphoneFactory:PhoneRelatedFactory{
func createPhone() -> Phone {
return IPhone()
}
func createUSB() -> USB {
return IphoneUSB()
}
}
//模拟不确定使用的产品
class func simulateFactory()->PhoneRelatedFactory{
let randomInt = random()%2
if randomInt == 0{
return SamsungFactory()
}else{
return IphoneFactory()
}
}
}
//测试代码
let factory = SimulateDynamicFactory.simulateFactory()
let phone = factory.createPhone()
let usb = factory.createUSB()
phone.call()
usb.use()
抽象工厂模式最重要的一句总结。
上面也说了不少关于抽象工厂涉及模式,其实只要掌握了工厂模式,抽象工厂模式用一句话就概括了:抽象工厂就是工厂的工厂,目的是使工厂也能按需动态创建
。
工厂模式 VS 抽象工厂模式
最后作为总结,简单的对比一下工厂模式和抽象工厂这两种设计模式。
工厂模式 VS 抽象工厂模式
网友评论