Mastering Redis Client Integration in Go with the Adapter Pattern
Learn how to use the Adapter pattern in Go to unify disparate Redis clients—*redis.Client* and *redis.ClusterClient*—by defining a common interface, implementing concrete adapters, and employing a factory method, resulting in cleaner, maintainable code that adheres to the open/closed principle.
Adapter Pattern Overview
The Adapter pattern is a structural design pattern that converts one interface into another expected by the client, allowing incompatible components to work together. It is useful during system upgrades or feature extensions where new and old interfaces differ.
Applying the Adapter Pattern to Redis Clients in Go
Go applications often interact with Redis using two main client types: *redis.Client and *redis.ClusterClient. Although their usage is similar, their interfaces are not identical, necessitating an adapter to manage them uniformly.
Defining a Common Interface
First, define a shared RedisClient interface that includes the common Redis operations needed by the application, such as Set and Get:
type RedisClient interface {
Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error
Get(ctx context.Context, key string) (string, error)
}Creating Concrete Adapters
Implement the interface for each concrete Redis client by creating two adapter structs: StandardClientAdapter for *redis.Client and ClusterClientAdapter for *redis.ClusterClient.
type StandardClientAdapter struct {
client *redis.Client
}
func (a *StandardClientAdapter) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
return a.client.Set(ctx, key, value, expiration).Err()
}
func (a *StandardClientAdapter) Get(ctx context.Context, key string) (string, error) {
return a.client.Get(ctx, key).Result()
}
type ClusterClientAdapter struct {
clusterClient *redis.ClusterClient
}
func (a *ClusterClientAdapter) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
return a.clusterClient.Set(ctx, key, value, expiration).Err()
}
func (a *ClusterClientAdapter) Get(ctx context.Context, key string) (string, error) {
return a.clusterClient.Get(ctx, key).Result()
}Factory Method for Adapter Creation
Introduce a factory function RedisClientFactory that receives a generic Redis configuration and returns the appropriate adapter instance, hiding the creation details from the caller.
func RedisClientFactory(redisConfig interface{}) (RedisClient, error) {
switch client := redisConfig.(type) {
case *redis.Client:
return &StandardClientAdapter{client: client}, nil
case *redis.ClusterClient:
return &ClusterClientAdapter{clusterClient: client}, nil
default:
return nil, fmt.Errorf("unsupported redis client type")
}
}Practical Usage Example
With the factory in place, application code can obtain a RedisClient without worrying about the underlying client type, then perform operations via the unified interface.
package main
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
func main() {
// Example: create a cluster client (standard client creation omitted for brevity)
clusterClient := redis.NewClusterClient(&redis.ClusterOptions{/* config */})
// Use the factory to get an adapter
client, _ := RedisClientFactory(clusterClient)
// Perform Redis operations through the adapter
client.Set(context.Background(), "key1", "value1", 0)
value, _ := client.Get(context.Background(), "key1")
fmt.Println("Got value:", value)
}Conclusion
The Adapter pattern provides a flexible and efficient solution for handling different Redis client types in Go. By introducing a common interface and concrete adapters, developers can extend system functionality and integrate new components without modifying existing code. Encapsulating adapter creation with a factory further hides implementation details, leading to cleaner, more maintainable code that respects the open/closed principle.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ops Development & AI Practice
DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
