当前位置:网站首页>Go interface oriented programming practice
Go interface oriented programming practice
2022-06-12 05:31:00 【Zen and the art of computer programming】

summary
Using interfaces allows us to write code that is easy to test , However, many engineers are right Go Their understanding of interfaces is very limited , I don't know the underlying implementation principle , This becomes development maintainable 、 Testable obstacles to good code .
This section will introduce some common problems encountered when using the interface and its design and implementation , Including the type conversion of the interface 、 Type assertion and dynamic dispatch mechanism , Help readers better understand interface types .
In computer science , Interface is the boundary shared by multiple components in a computer system , Different components can exchange information on boundaries . As shown in the figure below , The essence of the interface is to introduce a new middle layer , The caller can be separated from the concrete implementation through the interface , Uncoupling upstream and downstream , The modules in the upper layer no longer need to rely on the specific modules in the lower layer , You only need to rely on an agreed interface .

chart 1 The upstream and downstream are decoupled through the interface
This interface oriented programming method has a very strong vitality , No matter in the framework or operating system, we can find the figure of the interface . Portable operating system interface (Portable Operating System Interface,POSIX)2 It's a typical example , It defines standards such as application program interface and command line , Bring portability to computer software — As long as the operating system implements POSIX, Computer software can run directly on different operating systems .
In addition to decoupling dependent upstream and downstream , Interfaces can also help us hide the underlying implementation , Reduce focus .《 Construction and interpretation of computer program 》 There is such a sentence in" :
The code must be readable , Only the machine can just execute 3
The amount of information that people can process at the same time is very limited , Well defined interfaces can isolate the underlying implementation , Let's focus on the current snippet .
What is an interface ?
Definition
Official documents Chinese vs Interface That's how it's defined :
An interface type specifies a method set called its interface. A variable of interface type can store a value of any type with a method set that is any superset of the interface. Such a type is said to implement the interface. The value of an uninitialized variable of interface type is nil.
Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here. (https://go.dev/doc/effective_go#interfaces_and_types)
One interface Type defines a “ Set of functions ” As its interface .interface A variable of type can be saved containing the interface Values of any type in the superset of the type method set , At this time, we say this type Realization With this Interface . Uninitialized interface The zero value of the type variable is nil.
about interface Type of method set , Each of these methods must have a non repeating and not Filling name ( That is, single underline _) Method name of .
Dynamic distribution (Dynamic dispatch)
Go Interfaces are also called dynamic data types ( Abstract type ), When using interfaces , Will dynamically point to specific types ( Structure ).
Dynamic distribution (Dynamic dispatch) Is to select specific polymorphic operations during operation ( Method or function ) The process of execution , It is a common feature in object-oriented languages .Go Although language is not strictly object-oriented language , However, the introduction of the interface has brought the feature of dynamic distribution , When calling a method of interface type , If the type of interface cannot be confirmed during compilation ,Go The language will decide which implementation of the method to call during runtime .
The core of the type system
Go One of the main designers of language, rob · Parker once said :
If you can only select one Go The characteristics of language are transplanted to other languages , I will choose the interface .(Rob Pike)
Interface in Go Language has a crucial place . if goroutine and channel Is to support Go The cornerstone of the language's concurrency model , Give Way Go Language has become a very beautiful landscape in the era of clustering and multi-core , So the interface is Go The cornerstone of the whole type system of language , Give Way Go Language has reached an unprecedented height in the exploration of basic programming philosophy .
Go In language Interface The symbolic meaning of interface in object-oriented is weakened , Interface in Go Language is just “ form ” An abstract concept of the same kind of thing . stay Go As long as there is the same in the language “ form ” Of “ type ” All have the same Interface, Without having to think about this Interface It should have practical significance in specific use .
interface Characteristic summary
Is a set of function signatures
It's a type of
Interface oriented programming idea
Modules depend on interfaces to implement inheritance and polymorphism .
Inheritance and polymorphism are very good features of object-oriented design , It can better abstract the framework , Let the modules depend on the interface , Instead of relying on concrete implementations .
Rely on interfaces to implement method functions , As long as this interface is implemented, it can be regarded as assigned to this interface , Implement dynamic binding .
How to define an interface ?
type IInsightMultiMarketOverviewService interface {
GetMultiMarketSummaryPriceBandDistributionDataTable(ctx context.Context, multiMarketId int64, selfDefineId int64) ([]map[string]interface{}, error)
GetMultiMarketSummaryPriceBandDistributionQuadrant(ctx context.Context, multiMarketId int64) (*indexu.IQuadrantListType, error)
service_insight_multi_market.IInsightMultiMarketService
rocket.IRocketFetcher}type IInsightMultiMarketService interface {
// GetMultiIdTimeRange Access to multiple markets ID Of Analysis time frame and Compare the time range
GetMultiIdTimeRange(ctx context.Context, multiId int64) (analysisRange, comparisonRange *common.TimeRange, err error)
// GetMultiMarketAnalysisMap Access to multiple markets ID List of corresponding market segments
GetMultiMarketAnalysisMap(ctx context.Context, multiId int64) (analysisMarketMap map[int64]*model.BrandCustomerMarket, err error)
// GetMultiMarketComparisonId According to combination ID Get all of the following ( Analyze the market ID, Compare the market ID) Tuple information
GetMultiMarketAnalysisComparisonIds(ctx context.Context, multiId int64) (analysisComparisonIdRef []*model.BrandCustomerMultiMarketRef, err error)}type IRocketFetcher interface {
service.BasicInfoService
driver.INavigatorDriver}type RocketFetcher struct {
service.BasicInfoService
driver.INavigatorDriver}func NewRocketFetcher() *RocketFetcher {
return &RocketFetcher{
&service.BasicInfoServiceImpl{},
&driver.NavigatorDriver{},
}}How to implement interfaces ?
Defining interfaces :
type INavigatorDriver interface {
Query(ctx context.Context,
sqlKey,
sql string,
SearchOptions []*engine.Option,
SqlClient *sqlclient.SQLClient,
) ([]map[string]interface{}, error)}type NavigatorDriver struct {}func NewNavigatorDriver() *NavigatorDriver {
return &NavigatorDriver{}}Implementation interface :
// Query by sqlfunc (rcvr *NavigatorDriver) Query(Ctx context.Context,
sqlKey,
sql string,
SearchOptions []*engine.Option,
SqlClient *sqlclient.SQLClient,) ([]map[string]interface{}, error) {
logu.CtxInfo(Ctx, "Navigator Query", "sqlKey: %v, sql:%v", sqlKey, sql)
return NavigatorQueryList(Ctx, sqlKey, sql, SqlClient, SearchOptions...)}Performance considerations
Using structures to implement interfaces is more expensive than using pointers , And dynamic distribution is very poor on the structure . The huge performance difference caused by using structures is not just caused by interfaces , Performance issues , Mainly because Go Language passes values when calling functions , The process of dynamic distribution only magnifies the impact of parameter copy .
Types of assertions
Different operations are performed according to different types of variables .
① Type assertion method 1
func judgeType1(q interface{}) {
temp, ok := q.(string)
if ok {
fmt.Println(" Type conversion succeeded !", temp)
} else {
fmt.Println(" Type conversion failed !", temp)
}}① Type assertion method 2
Use switch...case... sentence , If the assertion is successful, go to the specified branch .
The code is as follows ( Example ):
code1: Common type
func judgeType2(q interface{}) {
switch i := q.(type) {
case string:
fmt.Println(" This is a string !", i)
case int:
fmt.Println(" It's an integer !", i)
case bool:
fmt.Println(" This is a boolean type !", i)
default:
fmt.Println(" Unknown type ", i)
}}code2: Pointer types
func main() {
var c Duck = &Cat{Name: "draven"}
switch c.(type) {
case *Cat:
cat := c.(*Cat)
cat.Quack()
}}Nesting of interfaces
Interfaces can be nested , Include small interfaces through large interfaces .
type IInsightMultiMarketOverviewService interface {
GetMultiMarketSummaryPriceBandDistributionDataTable(ctx context.Context, multiMarketId int64, selfDefineId int64) ([]map[string]interface{}, error)
GetMultiMarketSummaryPriceBandDistributionQuadrant(ctx context.Context, multiMarketId int64) (*indexu.IQuadrantListType, error)
service_insight_multi_market.IInsightMultiMarketService
rocket.IRocketFetcher}type IRocketFetcher interface {
service.BasicInfoService
driver.INavigatorDriver}type RocketFetcher struct {
service.BasicInfoService
driver.INavigatorDriver}func NewRocketFetcher() *RocketFetcher {
return &RocketFetcher{
&service.BasicInfoServiceImpl{},
&driver.NavigatorDriver{},
}}gomock The interface test
install mockgen Environmental Science , Generate mock Test pile code
Go Mock The interface test unit testing Minimalist tutorial :https://www.jianshu.com/p/abcb14f4bdf1
Go How to use nested combinations of interfaces & gomock test stub Code generation :https://www.jianshu.com/p/f1f09aa28ca9
gomock mockgen : unknown embedded interface: https://www.jianshu.com/p/a1233aa9347f
mockgen_service_insight_multi_market:
mockgen -source=./service/service_insight_multi_market/service_insight_multi_market.go -destination ./service/service_insight_multi_market/service_insight_multi_market_mock.go -package service_insight_multi_market
mockgen_service_insight_multi_market_overview:
mockgen -source=./service/service_insight_multi_market_overview/service_insight_multi_market_overview.go -destination ./service/service_insight_multi_market_overview/service_insight_multi_market_overview_mock.go -package service_insight_multi_market_overview -aux_files service_insight_multi_market_overview=./service/service_insight_multi_market/service_insight_multi_market.gomock Test code examples
func Test_InsightMultiMarketHandler_GetMultiMarketSummaryPriceBandDistributionDataTable(t *testing.T) {
ctx := context.Background()
multiMarketId := int64(123)
selfDefineId := int64(1)
ctrl := gomock.NewController(t)
defer ctrl.Finish()
MockIInsightMultiMarketService := service_insight_multi_market.NewMockIInsightMultiMarketService(ctrl)
// call InsightMultiMarketService.GetMultiIdTimeRange
MockIInsightMultiMarketService.
EXPECT().
GetMultiIdTimeRange(gomock.Any(), gomock.Any()).
Return(&common.TimeRange{StartDate: 1654701220}, &common.TimeRange{StartDate: 1653177600}, nil)
// call InsightMultiMarketService.GetMultiMarketAnalysisComparisonIds
MockIInsightMultiMarketService.
EXPECT().
GetMultiMarketAnalysisComparisonIds(gomock.Any(), gomock.Any()).
Return([]*model.BrandCustomerMultiMarketRef{
{MultiMarketID: 123, MarketID: 1, ComparisonID: 4},
{MultiMarketID: 123, MarketID: 2, ComparisonID: 5},
{MultiMarketID: 123, MarketID: 3, ComparisonID: 6},
}, nil)
// UIComponent only Render() Data functions
mockRocketFetcher := rocket.NewMockIRocketFetcher(ctrl)
mockRocketFetcher.
EXPECT().
Query(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
Return(driver.Mock_app_compass_strategy_multi_market_property_hi1())
mockRocketFetcher.
EXPECT().
Query(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
Return(driver.Mock_app_compass_strategy_multi_market_property_hi2())
s := &service_insight_multi_market_overview.InsightMultiMarketOverviewService{
MockIInsightMultiMarketService,
mockRocketFetcher,
}
result, _ := s.GetMultiMarketSummaryPriceBandDistributionDataTable(ctx, multiMarketId, selfDefineId)
fmt.Println("result=", convert.ToJSONString(result))
IInsightMultiMarketOverviewService := service_insight_multi_market_overview.NewMockIInsightMultiMarketOverviewService(ctrl)
IInsightMultiMarketOverviewService.
EXPECT().
GetMultiMarketSummaryPriceBandDistributionDataTable(gomock.Any(), gomock.Any(), gomock.Any()).
Return(result, nil)
InsightMultiMarketHandler := &InsightMultiMarketHandler{
service_insight_multi_market.NewInsightMultiMarketServiceHandler(),
IInsightMultiMarketOverviewService,
}
req := &multi_market_overview.MultiMarketSummaryPriceBandDistributionDataTableReq{
MultiMarketId: "123",
SelfDefineId: "1",
}
resp, _ := InsightMultiMarketHandler.GetMultiMarketSummaryPriceBandDistributionDataTable(ctx, req)
resultJSONString := convert.ToJSONString(resp)
fmt.Println("resp=", resultJSONString)
wanted := "{\"data\":{\"datatable\":[{\"dimention\":\"pay_amt\",\"dimention_name\":\" Sales amount \",\"price_brand\":\"-999\",\"index_info\":{\"value\":7924,\"out_period_incr\":-0.23476581361661034,..."
if resultJSONString != wanted {
t.Errorf("Test TestGetMultiMarketSummaryPriceBandDistributionDataTable failed, wanted %v, got %v", wanted, resultJSONString)
}}Interface implementation principle 【 High level 】
Reference resources :Go Interface implementation principle 【 High level 】:type _interface struct :
https://www.jianshu.com/p/93082b312512
summary
The interface is flexible , You can operate objects of this type in the implemented interface , Make interface method calls outside the interface , Implementing the same code snippet has different effects , The idea of polymorphism is also particularly important , Flexible use of interfaces , It is the desire of every programmer to make the program more flexible .
Reference material
https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-interface/
https://www.tapirgames.com/blog/golang-interface-implementation
https://go.dev/doc/effective_go#interfaces_and_types
https://blog.csdn.net/apple_51931783/article/details/122458612
https://blog.csdn.net/qq_21794823/article/details/78967719
https://blog.csdn.net/jacob_007/article/details/53557074
https://stackoverflow.com/questions/55999405/how-can-i-mock-specific-embedded-method-inside-interface
https://pkg.go.dev/github.com/golang/mock/gomock
https://github.com/golang/mock#running-mockgen
边栏推荐
猜你喜欢

Is the individual industrial and commercial door a legal person enterprise

Why should state-owned enterprises go public

Nature | 给全球的新冠伤亡算一笔账

WiFi band resources

Vivado HLS introductory notes

Nature | make an account of the new crown casualties in the world

Halcon 3D 1 读取3d数据

Matlab: image rotation and interpolation and comparison of MSE before and after

Save the object in redis, save the bean in redis hash, and attach the bean map interoperation tool class

Multi thread learning 4. Sleep, wait, yield, join (), ThreadGroup control the running of threads
随机推荐
FPGA语法的细节
Self implementation of a UI Library - UI core drawing layer management
Codis 3. X expansion and contraction
Caused by: org. h2.jdbc. JdbcSQLSyntaxErrorException: Table “USER“ already exists; SQL statement:
Halcon 用点来拟合平面
[getting to the bottom] five minutes to understand the combination evaluation model - fuzzy borde (taking the C question of the 2021 college students' numerical simulation national competition as an e
44. a digit in a sequence of digits
It costs less than 30 yuan, but we still don't build it quickly - check the small knowledge of software application
20. string representing numeric value
Summary of problems in rv1109/rv1126 product development
CentOS compiling and installing mysql8.0
62. the last number left in the circle
Pupanvr create project and management script (2)
Halcon 3D 深度图转换为3D图像
WiFi smartconfig implementation
Automated testing - Po mode / log /allure/ continuous integration
How does WiFi 802.11 correspond to 802.3
Serial port oscilloscope_ port_ Setup of plotter secondary development environment (including QT setup)
59 - II. Maximum value of the queue
Please remove any half-completed changes then run repair to fix the schema history