424 lines
11 KiB
Markdown
424 lines
11 KiB
Markdown
|
||
请按照如下内容继续重构和完善:
|
||
> 关键重构点说明:
|
||
>
|
||
> 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.
|