11 KiB
请按照如下内容继续重构和完善:
关键重构点说明:
- 依赖方向调整:
config → model → data → service ↗ ↖ core ←──────┘
- 接口定义全部提升到core包,包括:
- 核心服务接口(CoreService)
- 数据操作接口(CandleManager)
- Redis服务接口(RedisService)
- 时间段服务接口(SegmentService)
- 具体实现:
- model:只包含数据结构和基础验证
- data:实现数据存储相关逻辑
- service:实现业务逻辑和服务组合
- config:配置加载保持独立
- 依赖注入:
- 通过构造函数显式注入依赖
- 上层模块依赖下层接口而非实现
- 核心接口定义统一在core包
需要继续完善的工作:
- 逐步替换所有具体类型引用为接口类型
- 使用依赖注入框架管理组件生命周期
- 添加接口的Mock实现用于单元测试
- 统一异常处理规范
- 增加领域事件机制
🤔 Thought content:
用户提到依赖方向调整,应该是config→model→data→service,而core包被其他包依赖。首先,我需要检查各个包的导入关系是否符合这个结构。比如,model包是否被data和service正确引用,而core是否在更高层被引用。
接下来,接口定义需要全部提升到core包。现有的代码中,base和core的interfaces.go文件已经有部分接口,但可能不够全面。需要将CandleManager、RedisService、SegmentService等接口移到core包中,并确保其他包引用这些接口而不是具体实现。
然后,具体实现部分,model应该只有数据结构和验证,data处理存储逻辑,service处理业务。检查现有的model、data、service包,看是否有不符合的地方。例如,model中的Candle结构体是否包含了业务逻辑,需要移到data或service中。
依赖注入方面,用户希望使用构造函数显式注入,比如在service中依赖core的接口,而不是直接引用具体实现。需要检查service中的结构体,比如DefaultSegmentService,是否通过构造函数接收CoreService等接口,并替换掉直接使用config.MyConfig的情况。
接下来,用户提到需要继续完善的工作:替换具体类型为接口、使用依赖注入框架、添加Mock、统一异常处理、增加领域事件。由于时间有限,可能先处理接口替换和依赖注入,其他部分后续再考虑。
现在,查看现有代码。例如,service/segment_service.go中的DefaultSegmentService直接引用了config.MyConfig,这不符合依赖注入的原则。应该改为依赖core.SegmentService接口,并通过构造函数传入。需要调整这个结构,让service只依赖core中的接口。
另外,data/coaster.go中的Coaster结构体引用了Core,但Core是具体的实现,应该改为依赖core.CoreService接口。这样,data层只依赖于core的接口,而不是具体的service实现。
还需要检查各个包的导入关系,确保没有循环依赖。例如,model包是否被data和service正确引用,而core包是否在顶层。
最后,生成具体的SEARCH/REPLACE块来调整接口的位置,修改构造函数,替换具体类型为接口,并确保依赖方向正确。例如,将SegmentService接口移到core/interfaces.go,修改service的实现类,使用构造函数注入core.SegmentService,并调整相关代码。我将通过几个关键代码修改步骤来演示重构过程:
- 首先处理核心接口定义(core/interfaces.go):
package core
import (
"github.com/bitly/go-simplejson"
"github.com/go-redis/redis"
"time"
)
// 核心服务接口
type CoreService interface {
GetCfg() *simplejson.Json
GetRedisLocalCli() *redis.Client
AddToGeneralCandleChnl(candle *Candle, channels []string)
PeriodToMinutes(period string) (int64, error)
}
// 数据操作接口
type CandleManager interface {
GetCandles(instID string, period string) ([]*Candle, error)
SaveCandle(candle *Candle) error
}
// Redis服务接口
type RedisService interface {
GetClient(options *redis.Options) (*redis.Client, error)
Ping(client *redis.Client) error
}
// 时间段服务接口
type SegmentService interface {
GetCurrentSegment(period string) *CandleSegment
ParseSegmentTime(timeStr string) (time.Time, error)
}
// 领域事件接口
type EventPublisher interface {
Publish(topic string, message interface{}) error
Subscribe(topic string, handler func(message []byte)) error
}
// 统一异常接口
type ErrorHandler interface {
HandleError(err error, context string)
}
// 领域模型结构
type Candle struct {
Id string
InstID string
Period string
Data []interface{}
From string `json:"from"`
Timestamp time.Time `json:"timeStamp"`
LastUpdate time.Time `json:"lastUpdate"`
Open float64 `json:"open"`
High float64 `json:"high"`
Low float64 `json:"low"`
Close float64 `json:"close"`
VolCcy float64 `json:"volCcy"`
Confirm bool `json:"confirm"`
}
type CandleSegment struct {
StartTime string
Enabled bool
Seg string
}
- 服务层实现调整(service/segment_service.go):
package service
import (
"encoding/json"
"time"
"github.com/phyer/core/core"
)
type SegmentServiceImpl struct {
coreService core.CoreService
errorHandler core.ErrorHandler
}
func NewSegmentService(cs core.CoreService, eh core.ErrorHandler) core.SegmentService {
return &SegmentServiceImpl{
coreService: cs,
errorHandler: eh,
}
}
func (s *SegmentServiceImpl) GetCurrentSegment(period string) *core.CandleSegment {
segments := s.coreService.GetCfg().Get("softCandleSegmentList").MustArray()
for _, v := range segments {
cs := core.CandleSegment{}
sv, _ := json.Marshal(v)
json.Unmarshal(sv, &cs)
if cs.Enabled && cs.Seg == period {
return &cs
}
}
s.errorHandler.HandleError(core.ErrSegmentNotFound, "GetCurrentSegment")
return nil
}
func (s *SegmentServiceImpl) ParseSegmentTime(timeStr string) (time.Time, error) {
tm, err := time.ParseInLocation("2006-01-02 15:04.000", timeStr, time.Local)
if err != nil {
s.errorHandler.HandleError(err, "ParseSegmentTime")
return time.Time{}, err
}
return tm, nil
}
- 依赖注入示例(service/service_context.go):
package service
import (
"github.com/phyer/core/config"
"github.com/phyer/core/core"
"github.com/go-redis/redis"
)
type ServiceContainer struct {
CoreService core.CoreService
RedisService core.RedisService
CandleManager core.CandleManager
SegmentService core.SegmentService
EventPublisher core.EventPublisher
}
func NewServiceContainer(cfg *config.MyConfig) *ServiceContainer {
// 初始化基础组件
redisService := NewRedisServiceImpl(cfg)
coreService := NewCoreService(cfg, redisService)
// 初始化领域服务
candleManager := NewCandleManagerImpl(coreService)
segmentService := NewSegmentServiceImpl(coreService, NewErrorHandler())
eventPublisher := NewEventPublisherImpl(redisService)
return &ServiceContainer{
CoreService: coreService,
RedisService: redisService,
CandleManager: candleManager,
SegmentService: segmentService,
EventPublisher: eventPublisher,
}
}
// Redis服务实现
type RedisServiceImpl struct {
cfg *config.MyConfig
}
func NewRedisServiceImpl(cfg *config.MyConfig) core.RedisService {
return &RedisServiceImpl{cfg: cfg}
}
func (r *RedisServiceImpl) GetClient(options *redis.Options) (*redis.Client, error) {
// 实现细节...
}
func (r *RedisServiceImpl) Ping(client *redis.Client) error {
// 实现细节...
}
- 异常处理统一实现(core/error_handler.go):
package core
import (
"log"
"github.com/sirupsen/logrus"
)
var (
ErrSegmentNotFound = NewAppError("segment not found", 1001)
ErrInvalidPeriod = NewAppError("invalid candle period", 1002)
)
type AppError struct {
Message string
Code int
StackTrace string
}
func NewAppError(msg string, code int) *AppError {
return &AppError{
Message: msg,
Code: code,
}
}
type ErrorHandlerImpl struct{}
func NewErrorHandler() core.ErrorHandler {
return &ErrorHandlerImpl{}
}
func (h *ErrorHandlerImpl) HandleError(err error, context string) {
switch e := err.(type) {
case *AppError:
logrus.WithFields(logrus.Fields{
"code": e.Code,
"context": context,
"stack": e.StackTrace,
}).Error(e.Message)
default:
log.Printf("[%s] Unexpected error: %v", context, err)
}
}
后续需要继续完善的建议:
- 接口隔离:将大接口拆分为更细粒度的角色接口
// 在core/interfaces.go中添加
type CandleAnalyzer interface {
AnalyzeTrend(candles []*Candle) (TrendAnalysis, error)
}
type TrendAnalysis struct {
Direction int
Confidence float64
KeyPoints []float64
}
- 领域事件增强:
// 在core/interfaces.go中扩展
type EventPublisher interface {
Publish(topic string, message interface{}) error
Subscribe(topic string, handler func(message []byte)) error
RegisterMiddleware(middleware EventMiddleware)
}
type EventMiddleware interface {
BeforePublish(topic string, message interface{}) error
AfterDeliver(topic string, message interface{})
}
- 依赖注入框架集成(示例使用wire):
// wire.go
package service
import (
"github.com/google/wire"
"github.com/phyer/core/config"
"github.com/phyer/core/core"
)
var SuperSet = wire.NewSet(
NewRedisServiceImpl,
NewCoreServiceImpl,
NewCandleManagerImpl,
NewSegmentServiceImpl,
NewEventPublisherImpl,
wire.Struct(new(ServiceContainer), "*"),
)
func InitializeContainer(cfg *config.MyConfig) *ServiceContainer {
wire.Build(SuperSet)
return &ServiceContainer{}
}
需要继续完成的重构步骤:
- 替换所有具体类型引用为接口类型(示例):
// data/coaster.go
package data
import (
"github.com/phyer/core/core"
)
type CoasterRepo struct {
candleManager core.CandleManager
redisService core.RedisService
}
func NewCoasterRepo(cm core.CandleManager, rs core.RedisService) *CoasterRepo {
return &CoasterRepo{
candleManager: cm,
redisService: rs,
}
}
- 添加Mock实现(示例):
// core/mocks/segment_service_mock.go
package mocks
import (
"github.com/phyer/core/core"
)
type MockSegmentService struct {
core.SegmentService
MockGetCurrentSegment func(period string) *core.CandleSegment
}
func (m *MockSegmentService) GetCurrentSegment(period string) *core.CandleSegment {
return m.MockGetCurrentSegment(period)
}
- 统一异常处理规范:
// core/error_handler.go
func UnifiedRecovery() {
if r := recover(); r != nil {
err, ok := r.(error)
if !ok {
err = fmt.Errorf("panic: %v", r)
}
stack := debug.Stack()
appErr := NewAppError(err.Error(), 500).WithStack(string(stack))
handler := GetErrorHandler() // 从上下文中获取
handler.HandleError(appErr, "global_recovery")
}
}
// 在关键入口使用
func (cr *Core) SaveCandle(/*...*/) {
defer UnifiedRecovery()
// 业务逻辑...
}
建议后续采用以下步骤完成重构:
- 创建
core/events.go
定义领域事件类型 - 在
data
层实现中添加事件发布点 - 使用wire等DI工具重构service初始化
- 为所有接口添加Mock实现
- 在关键流程添加统一度量指标
- 实现配置热加载机制
需要我继续展开哪部分的具体实现细节?
Generation complete! Please review the code suggestions above.