package main
import (
"errors"
"fmt"
"net/http"
)
func LogOutput(message string) {
fmt.Println(message)
}
type SimpleDataStore struct {
userData map[string]string
}
func (sds SimpleDataStore) UserNameForID(userID string) (string, bool) {
name, ok := sds.userData[userID]
return name, ok
}
func NewSimpleDataStore() SimpleDataStore {
return SimpleDataStore{
userData: map[string]string{
"1": "Fred",
"2": "Mary",
"3": "Pat",
},
}
}
type DataStore interface {
UserNameForID(userID string) (string, bool)
}
type Logger interface {
Log(message string)
}
type LoggerAdapter func(message string)
func (lg LoggerAdapter) Log(message string) {
lg(message)
}
type SimpleLogic struct {
l Logger
ds DataStore
}
func (sl SimpleLogic) SayHello(userID string) (string, error) {
sl.l.Log("SayHello(" + userID + ")")
name, ok := sl.ds.UserNameForID(userID)
if !ok {
return "", errors.New("不明なユーザー")
}
return name + "さん、こんにちは。", nil
}
func (sl SimpleLogic) SayGoodbye(userID string) (string, error) {
sl.l.Log("SayGoodbye(" + userID + ")")
name, ok := sl.ds.UserNameForID(userID)
if !ok {
return "", errors.New("不明なユーザー")
}
return name + "さんさようなら。", nil
}
func NewSimpleLogic(l Logger, ds DataStore) SimpleLogic {
return SimpleLogic{
l: l,
ds: ds,
}
}
type Logic interface {
SayHello(userID string) (string, error)
}
type Controller struct {
l Logger
logic Logic
}
func (c Controller) SayHello(w http.ResponseWriter, r *http.Request) {
c.l.Log("SayHello内: ")
userID := r.URL.Query().Get("user_id")
message, err := c.logic.SayHello(userID)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
w.Write([]byte(message))
}
func NewController(l Logger, logic Logic) Controller {
return Controller{
l: l,
logic: logic,
}
}
func main() {
l := LoggerAdapter(LogOutput)
ds := NewSimpleDataStore()
logic := NewSimpleLogic(l, ds)
c := NewController(l, logic)
http.HandleFunc("/hello", c.SayHello)
http.ListenAndServe(":8080", nil)
}
func LogOutput(message string) {
fmt.Println(message)
}
-
LogOutput
関数を定義します。この関数は、引数として受け取ったメッセージをコンソールに出力します。
type SimpleDataStore struct {
userData map[string]string
}
-
SimpleDataStore
という構造体を定義します。この構造体は、ユーザーIDと名前のペアを保持するためのuserData
というマップを持っています。
func (sds SimpleDataStore) UserNameForID(userID string) (string, bool) {
name, ok := sds.userData[userID]
return name, ok
}
-
UserNameForID
メソッドを定義します。このメソッドは、ユーザーIDを引数に取り、そのIDに対応する名前を検索します。見つかった場合は名前とtrue
を、見つからなかった場合は空文字列とfalse
を返します。
func NewSimpleDataStore() SimpleDataStore {
return SimpleDataStore{
userData: map[string]string{
"1": "Fred",
"2": "Mary",
"3": "Pat",
},
}
}
-
NewSimpleDataStore
関数を定義します。この関数は、初期化されたSimpleDataStore
を返します。ここでは、ユーザーIDと名前のマッピングが設定されています。
type DataStore interface {
UserNameForID(userID string) (string, bool)
}
-
DataStore
インターフェースを定義します。このインターフェースは、UserNameForID
メソッドを要求します。これは、IDに基づいて名前を取得する機能を持つことを示しています。
type Logger interface {
Log(message string)
}
-
Logger
インターフェースを定義します。このインターフェースは、ログメッセージを出力するためのLog
メソッドを要求します。
type LoggerAdapter func(message string)
-
LoggerAdapter
という関数型を定義します。この型は、Log
メソッドを持つインターフェースに対応させるために使用されます。
func (lg LoggerAdapter) Log(message string) {
lg(message)
}
-
LoggerAdapter
にLog
メソッドを実装します。このメソッドは、受け取ったメッセージを関数として呼び出します。これにより、適応された関数がロギング機能を持つことができます。
type SimpleLogic struct {
l Logger
ds DataStore
}
-
SimpleLogic
という構造体を定義します。この構造体は、ロギング機能(l
)とデータストア(ds
)を持ちます。これにより、ビジネスロジックを実装する際に両方を使用できます。
func (sl SimpleLogic) SayHello(userID string) (string, error) {
sl.l.Log("SayHello(" + userID + ")")
name, ok := sl.ds.UserNameForID(userID)
if !ok {
return "", errors.New("不明なユーザー")
}
return name + "さん、こんにちは。", nil
}
-
SayHello
メソッドを定義します。このメソッドは、ユーザーIDを引数に取り、挨拶メッセージを生成します。- 最初に、
SayHello
が呼ばれたことをログに記録します。 - 次に、データストアからユーザー名を取得します。
- ユーザーが見つからない場合は、エラーを返します。
- ユーザーが見つかれば、挨拶メッセージを返します。
- 最初に、
func (sl SimpleLogic) SayGoodbye(userID string) (string, error) {
sl.l.Log("SayGoodbye(" + userID + ")")
name, ok := sl.ds.UserNameForID(userID)
if !ok {
return "", errors.New("不明なユーザー")
}
return name + "さんさようなら。", nil
}
-
SayGoodbye
メソッドもSayHello
と同様の構造ですが、さようならメッセージを生成します。
func NewSimpleLogic(l Logger, ds DataStore) SimpleLogic {
return SimpleLogic{
l: l,
ds: ds,
}
}
-
NewSimpleLogic
関数を定義します。この関数は、ロガー(l
)とデータストア(ds
)を受け取り、初期化されたSimpleLogic
を返します。
type Logic interface {
SayHello(userID string) (string, error)
}
-
Logic
インターフェースを定義します。このインターフェースは、SayHello
メソッドを要求します。これは、ユーザーIDに基づいて挨拶を行うロジックを持つことを示しています。
type Controller struct {
l Logger
logic Logic
}
-
Controller
構造体を定義します。この構造体は、ロギング機能(l
)とビジネスロジック(logic
)を持ちます。HTTPリクエストを処理する役割を持っています。
func (c Controller) SayHello(w http.ResponseWriter, r *http.Request) {
c.l.Log("SayHello内: ")
userID := r.URL.Query().Get("user_id")
message, err := c.logic.SayHello(userID)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
w.Write([]byte(message))
}
-
SayHello
メソッドを定義します。このメソッドは、HTTPリクエストを処理し、クエリパラメータからuser_id
を取得します。- 最初に、
SayHello
内でログを記録します。 - 次に、ユーザーIDを用いてビジネスロジックの
SayHello
メソッドを呼び出します。 - エラーが発生した場合は、HTTPステータスコード400(不正なリクエスト)を返し、エラーメッセージを表示します。
- エラーがなければ、生成されたメッセージをHTTPレスポンスとして返します。
- 最初に、
func NewController(l Logger, logic Logic) Controller {
return Controller{
l: l,
logic: logic,
}
}
-
NewController
関数を定義します。この関数は、ロガー(l
)とロジック(logic
)を受け取り、初期化されたController
を返します。
func main() {
l := LoggerAdapter(LogOutput)
ds := NewSimpleDataStore()
logic := NewSimpleLogic(l, ds)
c := NewController(l, logic)
http.HandleFunc("/hello", c.SayHello)
http.ListenAndServe(":8080", nil)
}
-
main
関数は、プログラムのエントリーポイントです。- 最初に、
LogOutput
関数をLoggerAdapter
としてラップします。 - 次に、
NewSimpleDataStore
を呼び出してデータストアを初期化します。 - その後、
NewSimpleLogic
を使ってビジネスロジックを初期化します。 -
NewController
を使ってコントローラーを初期化します。 -
http.HandleFunc
を使って、/hello
エンドポイントへのリクエストをSayHello
メソッドにマッピングします。 - 最後に、
http.ListenAndServe
を使って、ポート8080でHTTPサーバーを起動します。
- 最初に、
ブラウザで次のURLを表示してみてください(user_id= のあとに1, 2, 3などを指定)