重构前代码:https://www.jianshu.com/p/e5a3ba308aca
theatre.go
type Play struct {
Name string
Type string
}
type Plays map[string]Play
type Performance struct {
PlayID string
Audience int
}
type Invoices struct {
Customer string
Performances []Performance
}
func statement(invoices Invoices, plays Plays) (result string) {
param := NewStatementParam(invoices, plays)
data := NewStatementDate(param)
return data.packTxt()
}
theatre_data.go
type statementDate struct {
Customer string
PerfDataList []PerformanceData
TotalAmount float64
TotalCredits int
}
func NewStatementDate(param *statementParam) *statementDate {
s := &statementDate{}
s.Customer = param.invoices.Customer
s.PerfDataList = param.buildPerfDataList()
s.TotalAmount = s.totalAmount()
s.TotalCredits = s.totalCredits()
return s
}
func (s *statementDate) totalAmount() (totalAmount float64) {
for _, perf := range s.PerfDataList {
totalAmount += perf.ThisAmount
}
return totalAmount
}
func (s *statementDate) totalCredits() (totalCredits int) {
for _, perf := range s.PerfDataList {
totalCredits += perf.ThisCredits
}
return totalCredits
}
type PerformanceData struct {
PlayName string
ThisAmount float64
ThisCredits int
Audience int
}
func NewPerformanceData(playName string, thisAmount float64, thisCredits, audience int) PerformanceData {
return PerformanceData{
PlayName: playName,
ThisAmount: thisAmount,
ThisCredits: thisCredits,
Audience: audience,
}
}
theatre_pack.go
func (s *statementDate) packTxt() (result string) {
result = fmt.Sprintf("Statement for %s\n", s.Customer)
for _, data := range s.PerfDataList {
result += fmt.Sprintf(" %s: $%.2f(%d seats)\n", data.PlayName, data.ThisAmount, data.Audience)
}
result += fmt.Sprintf("Amount Owed is $%.2f\n", s.TotalAmount)
result += fmt.Sprintf("You earned %d credits\n", s.TotalCredits)
return result
}
func (s *statementDate) packHTML() (result string) {
return result
}
func (s *statementDate) packXML() (result string) {
return result
}
theatre_param.go
type statementParam struct {
invoices Invoices
plays Plays
}
func NewStatementParam(invoices Invoices, plays Plays) *statementParam {
return &statementParam{
invoices: invoices,
plays: plays,
}
}
func (s *statementParam) buildPerfDataList() []PerformanceData {
perfDataList := make([]PerformanceData, 0, len(s.invoices.Performances))
for _, perf := range s.invoices.Performances {
perfDataList = append(perfDataList, s.buildPerformanceData(perf))
}
return perfDataList
}
func (s *statementParam) buildPerformanceData(perf Performance) PerformanceData {
var (
playName = s.NameFor(perf)
thisAmount = s.thisAmountFor(perf)
thisCredits = s.thisCreditsFor(perf)
audience = perf.Audience
)
return NewPerformanceData(playName, thisAmount, thisCredits, audience)
}
func (s *statementParam) thisAmountFor(perf Performance) float64 {
var thisAmount int
switch s.TypeFor(perf) {
case "tragedy":
thisAmount = 40000
if perf.Audience > 30 {
thisAmount += 1000 * (perf.Audience - 30)
}
break
case "comedy":
thisAmount = 30000
if perf.Audience > 20 {
thisAmount += 10000 + 500*(perf.Audience-20)
}
thisAmount += 300 * perf.Audience
break
default:
panic(fmt.Sprintf("unknow type: %s", s.TypeFor(perf)))
}
return float64(thisAmount) / 100
}
func (s *statementParam) thisCreditsFor(perf Performance) (thisCredits int) {
thisCredits = util.Max(perf.Audience-30, 0)
if s.TypeFor(perf) == "comedy" {
thisCredits += perf.Audience / 5
}
return thisCredits
}
func (s *statementParam) TypeFor(perf Performance) string {
return s.plays[perf.PlayID].Type
}
func (s *statementParam) NameFor(perf Performance) string {
return s.plays[perf.PlayID].Name
}