作为初学者,我是不太容易理解简单工厂模式和工厂模式的区别,故整理一份笔记,供后续工作中查看.
简单工厂模式
(simple Factory Pattern)
简单工厂模式:需要定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有相同的父类.
简单工厂模式的优点:
工厂类包含必要的逻辑判断,可以选择在什么时候创建哪一个产品。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
客户端无需知道所创建具体产品的类名,只需知道参数即可。
也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类.
简单工厂模式的缺点:
简单工厂模式的工厂类单一,负责所有产品的创建,职责过大,一旦异常,正义都有影响,另外类工厂的代码会非常臃肿,违背高内聚原则
使用简单工厂模式会增加系统中类的个数, 增加系统的复杂度和理解度。
扩展困难,在产品类型过多时,可能造成逻辑过于复杂。
例如下述代码:
package desiginmodern
import "fmt"
type BaseDB struct {
address string
port int64
account string
passwd string
}
//Connect()应该返回的是连接对象,这里做了省略,所以用string来代替
type DBconnect interface {
Init(address string, port int64, account string, passwd string)
Connect() string
}
func (this *BaseDB) Init(address string, port int64, account string, passwd string) {
this.address = address
this.port = port
this.account = account
this.passwd = passwd
}
type MysqlDB struct {
BaseDB
}
func (mdb *MysqlDB) Connect() string {
return fmt.Sprintf("连接了mysql,地址是:%s", fmt.Sprintf("%s:%d", mdb.address, mdb.port))
}
type MongoDB struct {
BaseDB
}
func (mdb *MongoDB) Connect() string {
return fmt.Sprintf("mongo,地址是:%s", fmt.Sprintf("%s:%d", mdb.address, mdb.port))
}
type CreateDBFactory struct {
}
type CreateDBInter interface {
CreateDBConnect(dbname string) DBconnect
}
func (cdb *CreateDBFactory) CreateDBConnect(dbname string) (bdb DBconnect, err error) {
switch dbname {
case "mysql":
bdb = &MysqlDB{}
case "mongodb":
bdb = &MongoDB{}
default:
bdb = &MysqlDB{}
}
return
}
func main() {
dbFactory := &CreateDBFactory{}
mysqlObject, err := dbFactory.CreateDBConnect("mysql")
if err != nil {
panic("mysql error")
}
mysqlObject.Init("mysqladdress", 3306, "kengerukong", "kengerukong")
mysqlConnect := mysqlObject.Connect()
fmt.Println("mysql connect is " + mysqlConnect)
}
工厂模式
工厂方法模式,是简单工厂模式的进化版,是定义一个创建产品对象的工厂接口,工厂接口本身不去创建对象,而是交给其子类或者其实现类去创建,将实际创建工作推迟到子类中进行。
场景:
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现尤为明显。假如调用者自己组装产品需要增加依赖关系时,可以使用工厂模式,将会大大降低对象之间的耦合度。
由于工厂模式时依靠抽象架构的,它把实例化产品的任务交由实现类完成,扩展性较好。
优点:
在⼯⼚⽅法模式中,⼯⼚⽅法⽤来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被 实例化这⼀细 节,⽤户只需要关⼼所需产品对应的⼯⼚,⽆需关⼼创建细节,甚⾄⽆需知道具体产品类的类名。
基于⼯⼚⻆⾊和产品⻆⾊的多态性设计是⼯⼚⽅法模式的关键。它能够使⼯⼚可以⾃主确定创建何种 产品对象,⽽ 如何创建这个对象的细节则完全封装在具体⼯⼚内部。⼯⼚⽅法模式之所以⼜被称为多 态⼯⼚模式,正是因为所有的 具体⼯⼚类都具有同⼀抽象⽗类。
使⽤⼯⼚⽅法模式的另⼀个优点是在系统中加⼊新产品时,⽆需修改抽象⼯⼚和抽象产品提供的接 ⼝,⽆需修改客 户端,也⽆需修改其他的具体⼯⼚和具体产品,⽽只要添加⼀个具体⼯⼚和具体产品 就可以了,这样,系统的可扩展 性也就变得⾮常好,完全符合“开闭原则”。
缺点:
在添加新产品时,需要编写新的具体产品类,⽽且还要提供与之对应的具体⼯⼚类,系统中类的个数 将成对增加, 在⼀定程度上增加了系统的复杂度,有更多的类需要编译和运⾏,会给系统带来⼀些额 外的开销。
由于考虑到系统的可扩展性,需要引⼊抽象层,在客户端代码中均使⽤抽象层进⾏定义,增加了系统 的抽象性和理 解难度,且在实现时可能需要⽤到DOM、反射等技术,增加了系统的实现难度。
package desiginmodern
import "fmt"
type BaseDBV2 struct {
address string
port int64
account string
passwd string
}
//Connect()应该返回的是连接对象,这里做了省略,所以用string来代替
type DBconnectV2 interface {
InitV2(address string, port int64, account string, passwd string)
ConnectV2() string
}
func (this *BaseDBV2) InitV2(address string, port int64, account string, passwd string) {
this.address = address
this.port = port
this.account = account
this.passwd = passwd
}
type MysqlDBV2 struct {
BaseDBV2
}
func (mdb *MysqlDBV2) ConnectV2() string {
return fmt.Sprintf("连接了mysql,地址是:%s", fmt.Sprintf("%s:%d", mdb.address, mdb.port))
}
type MongoDBV2 struct {
BaseDBV2
}
func (mdb *MongoDBV2) ConnectV2() string {
return fmt.Sprintf("mongo,地址是:%s", fmt.Sprintf("%s:%d", mdb.address, mdb.port))
}
type CreateDBInterV2 interface {
CreateDBConnectV2() DBconnectV2
}
type CreateMysqlDBFactoryV2 struct {
}
func (cdb *CreateMysqlDBFactoryV2) CreateDBConnectV2() (bdb *MysqlDBV2, err error) {
bdb = &MysqlDBV2{}
return bdb, nil
}
type CreateMongodbDBFactoryV2 struct {
}
func (cdb *CreateMongodbDBFactoryV2) CreateDBConnectV2() (bdb *MongoDBV2, err error) {
bdb = &MongoDBV2{}
return bdb, nil
}
func main() {
mysqlFactory := &CreateMysqlDBFactoryV2{}
mysqlObject, err := mysqlFactory.CreateDBConnectV2()
if err != nil {
panic("mysql error")
}
mysqlObject.InitV2("mysqladdress", 3306, "kengerukong", "kengerukong")
mysqlConnect := mysqlObject.ConnectV2()
fmt.Println("mysql connect is " + mysqlConnect)
mongodbFactory := &CreateMongodbDBFactoryV2{}
mongodbObject, err := mongodbFactory.CreateDBConnectV2()
if err != nil {
panic("mongodb error")
}
mongodbObject.InitV2("mongodbaddress", 3307, "kengerukong", "kengerukong")
mongodbConnect := mongodbObject.ConnectV2()
fmt.Println("mongodb connect is " + mongodbConnect)