Go设计模式之Factory

分享到:

Overview


Factory - 工厂模式

工厂模式在Go中使用的非常广泛,比如常用于数据的读写模块。假设我们需要从某种介质中读取数据,并将更新后的结果保存到该介质中。考虑到以后可能更换为其他类型的介质,为了避免日后更换介质而大面积变更代码,我们就会用到本模式。

实现

1.定义工厂方法所创建对象的接口

假设我们的存储模块只有ReadWrite两个功能,我们需要先定义存储器inteface

1package store
2
3import "io"
4
5type Store interface {
6    Read(string) ([]byte, error)
7    Save(string, []byte) (error)
8}

2.实现对象接口

假设我们需要将Redis或磁盘作为存储介质,我们需要分别实现Redis与磁盘的存储功能。

FileSystem

 1pacakge store
 2
 3type FileStore struct{
 4  /*your codes*/
 5}
 6
 7func (store *FileStore) Read(string) ([]byte, error) {
 8  /*your codes*/
 9}
10
11func (store *FileStore) Save(string, []byte) (error) {
12  /*your codes*/
13}
14
15// 注意这里要返回 Store 接口,而不是FileStore的指针。
16// 可以保证工厂方法只能调用到对象接口方法,避免封装被破坏。
17func newFileStore() Store {
18  /*your codes*/
19}

Redis

 1pacakge store
 2
 3type RedisStore struct{
 4  /*your codes*/
 5}
 6
 7func (store *RedisStore) Read(string) ([]byte, error) {
 8  /*your codes*/
 9}
10
11func (store *RedisStore) Save(string, []byte) (error) {
12  /*your codes*/
13}
14
15// 注意这里要返回 Store 接口,而不是RedisStore的指针。
16// 可以保证工厂方法只能调用到对象接口方法,避免封装被破坏。
17func newRedisStore() Store {
18  /*your codes*/
19}

3.实现工厂方法

工厂方法是暴露给模块外部使用的,用于创建实例的方法。我们需要将各种类型Store实例的创建过程封装到该方法里面,避免暴露给外部模块。由工厂方法统一提供创建功能。

 1pacakge store
 2
 3type (
 4  StoreType int
 5)
 6
 7const (
 8  File StorageType = 1 << iota
 9  Redis
10)
11
12func NewStore(storeType StoreType) Store {
13  switch storeType {
14    case File:
15      return newFileStore()
16    case Redis:
17      return newRedisStore()
18    default:
19      panic("尚未支持的存储类型!")
20  }
21}

使用

假设我们需要使用Redis作为存储介质,我们只需要在工厂方法中传入store.Redis参数。

 1package main
 2
 3import (
 4  "fmt"
 5
 6  "xxxx/store" // 你的模块地址
 7)
 8
 9func main() {
10  st := store.NewStore(store.Redis)
11
12  // 读取数据
13  data, err := st.Read("/foo")
14  fmt.Println(err, data)
15
16  // 保存数据
17  err = st.Write("/foo", data)
18  fmt.Println(err)
19}

如果现在我们想更换介质为文件系统,我们只需要更换工厂方法中传入的参数为store.File即可完成介质更换。

1// 其他代码不变
2
3// 工厂方法的参数更改为store.File即可。
4st := store.NewStore(store.File)
5
6// 其他代码不变
comments powered by Disqus