Go和Java实现抽象工厂模式
本文通过简单数据库操作案例来说明抽象工厂模式的使用,使用Go语言和Java语言实现。
1、抽象工厂模式
抽象工厂模式是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创
建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工
厂模式提供对象。
-
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
-
主要解决:主要解决接口选择的问题。
-
何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
-
如何解决:在一个产品族里面,定义多个产品。
-
关键代码:在一个工厂里聚合多个同类产品。
-
应用实例:工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产
品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、
时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,但有利于说明抽象工
厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每
次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是
衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产
品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。
-
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
-
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里
面加代码。
-
使用场景:1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。
-
注意事项:产品族难扩展,产品等级易扩展。
-
适用性:
一个系统要独立于它的产品的创建、组合和表示时。
一个系统要由多个产品系列中的一个来配置时。
当你要强调一系列相关的产品对象的设计以便进行联合使用时。
当你提供一个产品类库,而只想显示它们是接口而不是实现时。
2、Go实现简单数据库操作
我们通过 sqlserver 和 access 两种数据库对用户表和部门表进行操作。
package factory// 操作的用户表
type User struct {Id intName string
}
package factory// 用户表的操作
type IUser interface {InsertUser(User) boolGetUser(int)
}
package factoryimport "fmt"// SqlServer数据库操作用户表
type SqlServerUser struct {
}func (sqlServerUser *SqlServerUser) InsertUser(user User) bool {fmt.Println("SqlServer数据库插入用户!")return true
}func (sqlServerUser *SqlServerUser) GetUser(int) {fmt.Println("SqlServer数据库查询用户!")
}
package factoryimport "fmt"// Access数据库操作用户表
type AccessUser struct {
}func (accessUser *AccessUser) InsertUser(user User) bool {fmt.Println("Access数据库插入用户!")return true
}func (accessUser *AccessUser) GetUser(int) {fmt.Println("Access数据库查询用户!")
}
package factory// 操作的部门表
type Deployment struct {Id intName string
}
package factory// 部门表的操作
type IDeployment interface {InsertDeployment(Deployment) boolGetDeployment(int)
}
package factoryimport "fmt"// SqlServer数据库操作部门表
type SqlServerDeployment struct {
}func (sqlServerDeployment *SqlServerDeployment) InsertDeployment(deployment Deployment) bool {fmt.Println("SqlServer数据库插入部门!")return true
}func (sqlServerDeployment *SqlServerDeployment) GetDeployment(int) {fmt.Println("SqlServer数据库查询部门!")
}
package factoryimport "fmt"// Access数据库操作部门表
type AccessDeployment struct {
}func (accessDeployment *AccessDeployment) InsertDeployment(deployment Deployment) bool {fmt.Println("Access数据库插入部门!")return true
}func (accessDeployment *AccessDeployment) GetDeployment(int) {fmt.Println("Access数据库查询部门!")
}
package factory// 创建用户和部门操作的接口
type IFactory interface {CreateUser() IUserCreateDeployment() IDeployment
}
package factory// Access数据库工厂
type AccessFactory struct {
}func (accessFactory *AccessFactory) CreateUser() IUser {return &AccessUser{}
}func (accessFactory *AccessFactory) CreateDeployment() IDeployment {return &AccessDeployment{}
}
package factory// SqlServer数据库工厂
type SqlServerFactory struct {
}func (sqlServerFactory *SqlServerFactory) CreateUser() IUser {return &SqlServerUser{}
}func (sqlServerFactory *SqlServerFactory) CreateDeployment() IDeployment {return &SqlServerDeployment{}
}
package constantconst (SqlServer = "sqlserver"Access = "access"
)
package factoryimport "proj/constant"// 用一个简单工厂封装抽象工厂
type FactoryCreate struct {
}func (factoryCreate *FactoryCreate) NewFactory(dbType string) IFactory {switch dbType {case constant.SqlServer:return &SqlServerFactory{}case constant.Access:return &AccessFactory{}}return nil
}
package mainimport ("fmt""proj/constant". "proj/factory"
)// 测试
func main() {// 全局变量var factory IFactoryvar iUser IUservar iDeployment IDeployment// 操作用户user := User{}deployment := Deployment{}// SqlServer操作factory = &SqlServerFactory{}iUser = factory.CreateUser()iUser.InsertUser(user)iUser.GetUser(1)iDeployment = factory.CreateDeployment()iDeployment.InsertDeployment(deployment)iDeployment.GetDeployment(1)// Access操作factory = &AccessFactory{}iUser = factory.CreateUser()iUser.InsertUser(user)iUser.GetUser(1)iDeployment = factory.CreateDeployment()iDeployment.InsertDeployment(deployment)iDeployment.GetDeployment(1)fmt.Println("========================")// 简单工厂封装工厂方法factoryCreate := FactoryCreate{}// ==========SqlServer的工厂==========factory = factoryCreate.NewFactory(constant.SqlServer)iUser = factory.CreateUser()iUser.InsertUser(user)iUser.GetUser(1)iDeployment = factory.CreateDeployment()iDeployment.InsertDeployment(deployment)iDeployment.GetDeployment(1)// ==========Access的工厂==========factory = factoryCreate.NewFactory(constant.Access)iUser = factory.CreateUser()iUser.InsertUser(user)iUser.GetUser(1)iDeployment = factory.CreateDeployment()iDeployment.InsertDeployment(deployment)iDeployment.GetDeployment(1)
}
# 程序输出
SqlServer数据库插入用户!
SqlServer数据库查询用户!
SqlServer数据库插入部门!
SqlServer数据库查询部门!
Access数据库插入用户!
Access数据库查询用户!
Access数据库插入部门!
Access数据库查询部门!
========================
SqlServer数据库插入用户!
SqlServer数据库查询用户!
SqlServer数据库插入部门!
SqlServer数据库查询部门!
Access数据库插入用户!
Access数据库查询用户!
Access数据库插入部门!
Access数据库查询部门!
3、Java实现简单数据库操作
package com.factory;// 操作的用户表
public class User {private int Id;private String Name;public int getId() {return Id;}public void setId(int id) {Id = id;}public String getName() {return Name;}public void setName(String name) {Name = name;}
}
package com.factory;// 用户表的操作
public interface IUser {boolean InsertUser(User user);void GetUser(int id);
}
package com.factory;// SqlServer数据库操作用户表
public class SqlServerUser implements IUser {@Overridepublic boolean InsertUser(User user) {System.out.println("SqlServer数据库插入用户!");return true;}@Overridepublic void GetUser(int id) {System.out.println("SqlServer数据库查询用户!");}
}
package com.factory;// Access数据库操作用户表
public class AccessUser implements IUser {@Overridepublic boolean InsertUser(User user) {System.out.println("Access数据库插入用户!");return true;}@Overridepublic void GetUser(int id) {System.out.println("Access数据库查询用户!");}
}
package com.factory;// 操作的部门表
public class Deployment {private int Id;private String Name;public int getId() {return Id;}public void setId(int id) {Id = id;}public String getName() {return Name;}public void setName(String name) {Name = name;}
}
package com.factory;// 部门表的操作
public interface IDeployment {boolean InsertDeployment(Deployment deployment);void GetDeployment(int id);
}
package com.factory;// Access数据库操作部门表
public class AccessDeployment implements IDeployment {@Overridepublic boolean InsertDeployment(Deployment deployment) {System.out.println("Access数据库插入部门!");return true;}@Overridepublic void GetDeployment(int id) {System.out.println("Access数据库查询部门!");}
}
package com.factory;// SqlServer数据库操作部门表
public class SqlServerDeployment implements IDeployment {@Overridepublic boolean InsertDeployment(Deployment deployment) {System.out.println("SqlServer数据库插入部门!");return true;}@Overridepublic void GetDeployment(int id) {System.out.println("SqlServer数据库查询部门!");}
}
package com.factory;// 创建用户和部门操作的接口
public interface IFactory {IUser CreateUser();IDeployment CreateDeployment();
}
package com.factory;// Access数据库工厂
public class AccessFactory implements IFactory {@Overridepublic IUser CreateUser() {return new AccessUser();}@Overridepublic IDeployment CreateDeployment() {return new AccessDeployment();}
}
package com.factory;// SqlServer数据库工厂
public class SqlServerFactory implements IFactory {@Overridepublic IUser CreateUser() {return new SqlServerUser();}@Overridepublic IDeployment CreateDeployment() {return new SqlServerDeployment();}
}
package com.factory;// 用一个简单工厂封装抽象工厂
public class FactoryCreate {public IFactory NewFactory(DbType dbType) {switch (dbType) {case SQLSERVER:return new SqlServerFactory();case ACCESS:return new AccessFactory();}return null;}
}
package com.factory;public class Test {public static void main(String[] args) {// 全局变量IFactory factory = null;IUser iUser = null;IDeployment iDeployment = null;// 操作用户User user = new User();Deployment deployment = new Deployment();// SqlServer操作factory = new SqlServerFactory();iUser = factory.CreateUser();iUser.InsertUser(user);iUser.GetUser(1);iDeployment = factory.CreateDeployment();iDeployment.InsertDeployment(deployment);iDeployment.GetDeployment(1);// Access操作factory = new AccessFactory();iUser = factory.CreateUser();iUser.InsertUser(user);iUser.GetUser(1);iDeployment = factory.CreateDeployment();iDeployment.InsertDeployment(deployment);iDeployment.GetDeployment(1);System.out.println("========================");// 简单工厂封装工厂方法FactoryCreate factoryCreate = new FactoryCreate();// ==========SqlServer的工厂==========factory = factoryCreate.NewFactory(DbType.SQLSERVER);iUser = factory.CreateUser();iUser.InsertUser(user);iUser.GetUser(1);iDeployment = factory.CreateDeployment();iDeployment.InsertDeployment(deployment);iDeployment.GetDeployment(1);// ==========Access的工厂==========factory = factoryCreate.NewFactory(DbType.ACCESS);iUser = factory.CreateUser();iUser.InsertUser(user);iUser.GetUser(1);iDeployment = factory.CreateDeployment();iDeployment.InsertDeployment(deployment);iDeployment.GetDeployment(1);}}
# 程序输出
SqlServer数据库插入用户!
SqlServer数据库查询用户!
SqlServer数据库插入部门!
SqlServer数据库查询部门!
Access数据库插入用户!
Access数据库查询用户!
Access数据库插入部门!
Access数据库查询部门!
========================
SqlServer数据库插入用户!
SqlServer数据库查询用户!
SqlServer数据库插入部门!
SqlServer数据库查询部门!
Access数据库插入用户!
Access数据库查询用户!
Access数据库插入部门!
Access数据库查询部门!
4、简单工厂和工厂方法和抽象工厂类的区别
一句话概括工厂模式:
-
简单工厂:一个工厂类,一个产品抽象类。
-
工厂方法:多个工厂类,一个产品抽象类。
-
抽象工厂:多个工厂类,多个产品抽象类。
生活中的工厂模式:
-
简单工厂类:一个麦当劳店,可以生产多种汉堡。
-
工厂方法类:一个麦当劳店,可以生产多种汉堡。一个肯德基店,也可以生产多种汉堡。
-
抽象工厂类:百胜餐饮集团下有肯德基和百事公司,肯德基生产汉堡,百事公司生成百事可乐。
区别:
-
简单工厂:只有唯一工厂(简单工厂),一个产品接口/抽象类,根据简单工厂中的静态方法来创建具体产品对
象,适用于产品较少,几乎不扩展的情景。简单工厂中的方法集中了所有产品创建的逻辑,一旦要拓展新产品
时,就不得不修改工厂类,并且会造成工厂的逻辑过于复杂,开发中很少使用。
-
工厂方法:有多个工厂(抽象工厂+多个具体工厂),一个产品接口/抽象类,根据继承抽象工厂中的方法来多态
创建具体产品对象,适用于一个类型的多个产品。工厂方法模式中,在新增一个新产品时,就要新增一个具体
工厂和一个具体产品类,这样程序的拓展性就有了提高,符合了开闭原则,避免了简单工厂模式的缺点,但是
新增产品时需要新增两个类,会增加代码量,可谓是有舍有得,具体如何要结合具体情况来使用,开发中经常
使用。
-
抽象方法:有多个工厂(抽象工厂+多个具体工厂),多个产品接口/抽象类,对产品子类进行分组,根据继承
抽象工厂中的方法多态创建同组的不同具体产品对象,适用于多个类型的多个产品。抽象工厂模式是所有工厂
模式的一般形式,当抽象工厂模式退化到只有一个产品等级结构时,就变成了工厂方法模式。当工厂方法模式
的工厂类只有一个时,且工厂方法为静态方法时,则又变成了简单工厂模式。与工厂方法模式相似,抽象工厂
模式隔离了具体类的生成,让客户端不清楚具体什么样的对象被创建。
抽象⼯⼚模式与⼯⼚⽅法模式虽然主要意图都是为了解决接⼝选择问题,但在实现上抽象⼯⼚是一个中⼼⼯⼚,创
建其他⼯⼚的模式。