zhangkun9038@dingtalk.com 4380e95e00 2025-04-07 13:07:53: ...
2025-04-07 13:08:02 +08:00

424 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

请按照如下内容继续重构和完善:
> 关键重构点说明:
>
> 1. 依赖方向调整:
> ```
> config → model → data → service
> ↗ ↖
> core ←──────┘
> ```
>
> 2. 接口定义全部提升到core包包括
> - 核心服务接口CoreService
> - 数据操作接口CandleManager
> - Redis服务接口RedisService
> - 时间段服务接口SegmentService
>
> 1. 具体实现:
> - model只包含数据结构和基础验证
> - data实现数据存储相关逻辑
> - service实现业务逻辑和服务组合
> - config配置加载保持独立
>
> 2. 依赖注入:
> - 通过构造函数显式注入依赖
> - 上层模块依赖下层接口而非实现
> - 核心接口定义统一在core包
>
> 需要继续完善的工作:
>
> 3. 逐步替换所有具体类型引用为接口类型
> 4. 使用依赖注入框架管理组件生命周期
> 5. 添加接口的Mock实现用于单元测试
> 6. 统一异常处理规范
> 7. 增加领域事件机制
>
🤔 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并调整相关代码。我将通过几个关键代码修改步骤来演示重构过程
1. 首先处理核心接口定义core/interfaces.go
```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
}
```
2. 服务层实现调整service/segment_service.go
```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
}
```
1. 依赖注入示例service/service_context.go
```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 {
// 实现细节...
}
```
2. 异常处理统一实现core/error_handler.go
```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)
}
}
```
后续需要继续完善的建议:
3. 接口隔离:将大接口拆分为更细粒度的角色接口
```go
// 在core/interfaces.go中添加
type CandleAnalyzer interface {
AnalyzeTrend(candles []*Candle) (TrendAnalysis, error)
}
type TrendAnalysis struct {
Direction int
Confidence float64
KeyPoints []float64
}
```
4. 领域事件增强:
```go
// 在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{})
}
```
5. 依赖注入框架集成示例使用wire
```go
// 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{}
}
```
需要继续完成的重构步骤:
6. 替换所有具体类型引用为接口类型(示例):
```go
// 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,
}
}
```
7. 添加Mock实现示例
```go
// 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)
}
```
8. 统一异常处理规范:
```go
// 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()
// 业务逻辑...
}
```
建议后续采用以下步骤完成重构:
9. 创建`core/events.go`定义领域事件类型
10.`data`层实现中添加事件发布点
11. 使用wire等DI工具重构service初始化
12. 为所有接口添加Mock实现
13. 在关键流程添加统一度量指标
14. 实现配置热加载机制
需要我继续展开哪部分的具体实现细节?
**Generation complete!** Please review the code suggestions above.