在中国历史上,房子经常与当下同样稀缺,住房问题一样是一个让百姓苦恼的社会热点。git
在拆违章建筑还不盛行的年代,咱们能够选择在深山老林里本身修建住所。在 Java 中多是这样实现的:github
class BuildingA {
private String name;
public BuildingA(String name) {
this.name = name;
}
public void build() {
System.out.println(name + " is building");
}
}
class BuildingB {
private String name;
public BuildingB(String name) {
this.name = name;
}
public void build() {
System.out.println(name + " is building");
}
}
// 使用
BuildingA buildingA = new BuildingA("bedroom");
BuildingB buildingB = new BuildingB("kitchen");
buildingA.build();
buildingB.build();复制代码
村里的牛大哥在建完两间房子以后,后知后觉:本身想要的房间格局不一样,可是风格得相同,能够把公共的部分抽离出来:设计模式
interface IBuilding {
void build();
}
abstract class AbstractBuilding implements IBuilding {
protected void buildCommon(){
System.out.println("Europe style"); // 公共的部分
}
}
class BuildingAs extends AbstractBuilding {
private String name;
public BuildingAs(String name){
this.name = name;
}
@Override
public void build() {
this.buildCommon();
System.out.println(name + " is building");
}
}
class BuildingBs extends AbstractBuilding {
private String name;
public BuildingBs(String name) {
this.name = name;
}
@Override
public void build() {
this.buildCommon();
System.out.println(name + " is building");
}
}
// 使用
BuildingAs buildingA = new BuildingAs("bedroom");
BuildingBs buildingB = new BuildingBs("kitchen");
buildingA.build();
buildingB.build();复制代码
可是这么作以后,牛大哥发如今建造的时候并无省力,他向村口的王师傅请教,为何我考虑了不少反而没什么做用呢?app
王师傅告诉他:虽然你找出了一些公共的流程,但在实际建造过程当中,你仍是完整的过了全部的流程(构造方法不一样,每次都要 new
对象)。另外,ide
另外,你对房屋的需求并很少,因此优点不够明显。函数
说着掏出一个宝盒,盒子里有不少设计图:下次你能够委托我来造一些组件(再也不须要本身 new
):测试
public class SimpleFactory {
public static IBuilding getProduct(String name){
if("bedroom".equals(name)){
return new BuildingA(name);
}else if("kitchen".equals(name)){
return new BuildingB(name);
}else{
throw new IllegalArgumentException();
}
}
}
// 使用
IBuilding buildingA = SimpleFactory.getProduct("bedroom");
IBuilding buildingB = SimpleFactory.getProduct("kitchen");
buildingA.build();
buildingB.build();复制代码
王师傅帮助下的牛大哥在后面的建造中感受轻松多了。ui
这就是「简单工厂模式」,也称做「静态工厂方法模式」。this
它有如下几个优势:spa
而牛二哥明显没有那么幸运,他的妻子追求个性,而且很善变,老是在建造过程当中更改需求。
虽然牛二哥也去王师傅那获取组件,每次王师傅都要拿出他的宝盒,在里面翻一遍,再告诉牛二哥 —— 这个我不会造。站在 OCP(开放封闭原则)的角度讲,该模式的扩展不够良好,每次有新的模型后都要修改工厂。
老王师傅也经不起折腾,想着不能闭关锁国,就把本身会建造的组件贴在显眼的地方,有新的组件直接加在上面就好:
interface IFactory {
public IBuilding createBuilding();
}
class FactoryA implements IFactory{
@Override
public IBuilding createBuilding() {
// 能够进行复杂的处理,每一种方法对应一种模型
return new BuildingA("bedroom");
}
}
class FactoryB implements IFactory{
@Override
public IBuilding createBuilding() {
return new BuildingA("kitchen");
}
}
class FactoryC implements IFactory{
@Override
public IBuilding createBuilding() {
return new BuildingA("restroom");
}
}
// 使用
FactoryA factoryA = new FactoryA();
FactoryB factoryB = new FactoryB();
FactoryC factoryC = new FactoryC();
factoryA.createBuilding();
factoryB.createBuilding();
factoryC.createBuilding();复制代码
这样你们的沟通是方便了不少,并且老王也不用每次都搜一遍传家宝盒。
这种模式被 GOF 称做「工厂方法模式」。
工厂方法模式(Factory Method Pattern)是一种实现了「工厂」概念的面向对象设计模式。就像其余建立型模式同样,它也是 处理在不指定对象具体类型的状况 下建立对象的问题。定义以下:
定义一个用于建立对象的接口,让子类决定实例化哪个类。Factory Method 使一个类的实例化延迟到其子类。 — 《设计模式》 GOF
从以上也可看出:工厂作的事很简单 —— 封装内部的实现细节。
它能够带来如下好处:
咱们可能会赶上如下问题:
工厂方法模式针对的是一个产品等级结构,当要处理多个产品等级结构时(ex. 创建不一样小区,小区里有不一样楼宇,楼里还有不一样户型),咱们不但愿对每一个模型都创建一个工厂,这太糟糕了,来看看「抽象工厂模式」是如何解决的。
为建立一组相关或相互依赖的对象提供一个接口,并且无需指定他们的具体类。
咱们也可把「一组相关或相互依赖的对象」称做「产品族」。
利用抽象工厂,咱们能够这么写:
interface IBuildingA {
void buildA();
}
interface IBuildingB {
void buildB();
}
interface IFactory {
public IBuildingA createBuildingA();
public IBuildingB createBuildingB();
}
class BuildingA implements IBuildingA {
... // 省略构造函数
@Override
public void buildA() {
System.out.println((name + "is building"));
}
}
class BuildingB implements IBuildingB {
... // 省略构造函数
@Override
public void buildB() {
System.out.println(name + " is building");
}
}
class Factory implements IFactory{
@Override
public IBuildingA createBuildingA() {
return new BuildingA("big bedroom");
}
@Override
public IBuildingB createBuildingB() {
return new BuildingB("small bedroom");
}
}
// 测试
Factory factory = new Factory();
factory.createBuildingA();
factory.createBuildingB();复制代码
咱们能够直接在一个工厂类中实现多个方法,这样不用管理多个工厂,使用和管理起来都更方便。
若是说工厂方法解决问题的方式是「广搜」,那抽象工厂亦可看做「深搜」。
以上,咱们使用到了三种设计模式:简单工厂(静态工厂方法)、工厂方法、抽象工厂。
在三种模式中,咱们要作的都是将工厂的初始化与构造分离。
虽然比起直接 new
要增长很多代码,但在后期维护的时候,能给咱们提供不少的便利。
看完 Java 版本,咱们再来看看 Scala 是如何实现的。
在 Scala 中,依旧能够用相似 Java 的方式来实现,只用把 Java 中的关键字 interface
换成 trait
便可,直接看代码吧。
trait IBuilding {
def show()
}
case class SimpleBuilding(name: String)extends IBuilding {
def show = println("SimpleBuilding " + name + " is building")
}
case class LuxuryBuilding(name: String) extends IBuilding{
def show = println("LuxuryBuilding " + name + " is building")
}
object ConstructionFactory {
def createBuilding(kind: String): IBuilding = kind match {
case "Simple" => SimpleBuilding("Simple")
case "Luxury" => LuxuryBuilding("Luxury")
}
}
object Test extends App {
val simpleBuilding: IBuilding = ConstructionFactory.createBuilding("Simple")
val luxuryBuilding: IBuilding = ConstructionFactory.createBuilding("Luxury")
simpleBuilding.show()
luxuryBuilding.show()
}复制代码
除了这种方式,Scala 还为咱们提供了一种相似构造器的语法 —— apply
,经过这种方式,咱们能够省略工厂类,只需增长产品类接口的伴生对象:
object IBuilding {
def apply(kind: String): IBuilding = kind match {
case "Simple" => SimpleBuilding("Simple")
case "Luxury" => LuxuryBuilding("Luxury")
}
}复制代码
调用者有更好的体验:
val simpleBuilding: IBuilding = IBuilding("Simple")
val luxuryBuilding: IBuilding = IBuilding("Luxury")
simpleBuilding.show()
luxuryBuilding.show()复制代码
严格意义讲,这种方法并不属于 GOF 提到的工厂方法,它缺乏了工厂模块,咱们能够称之为「静态工厂模式」。
工厂方法与抽象工厂的实现与 Java 相似,代码就不贴出来了。不了解 Scala 的同窗能够参考源码
以上,不难总结出工厂模式中的四种角色(简单工厂模式中没有抽象工厂):
IBuiiding
)。Buiiding
)Factory Method
),用于返回一个产品。抽象工厂是工厂方法模式的核心,全部建立对象的工厂类都必须实现该接口。(ex. 文中 IFactory
)ConstructionFactory
)固然,咱们不能为了设计而设计,当类结构简单的时候,咱们能够直接使用 new
来创造,不然会增长没必要要的代码,反而使结构复杂化。
全部工厂模式适用场景相似:调用者无需知道他所使用的对象的类(实际上内部结构对调用者是透明的 ex. 简单工厂)。
但仍是有所差别,如下为我的理解:
名称 | 适用场景 |
---|---|
简单工厂 | 1. 工厂类负责建立的对象比较少 2. 客户只知道传入工厂类的参数,对于如何建立对象(逻辑)不关心 |
工厂方法 | 工厂类负责建立的对象复杂, 且内部对象层级关系比较简单 |
抽象工厂 | 工厂类负责建立的对象复杂, 且内部对象层级关系比较复杂 |
若有错误和讲述不恰当的地方还请指出,不胜感激!