<aside> 💡
중복 코드는 변경을 방해한다
</aside>
class Call
{
public:
Call(const FLocalDateTime& InFrom, const FLocalDateTime& InTo)
: From(InFrom)
, To(InTo)
{}
FDuration GetDuration() const { return FDuration::Between(From, To); }
FLocalDateTime GetFrom() const { return From; }
private:
FLocalDateTime From;
FLocalDateTime To;
};
class FPhone
{
public:
FPhone(FMoney* InAmount, const FDuration& InSeconds)
: Amount(InAmount)
, Seconds(InSeconds)
{}
void Call(FCall* InCall) { Calls.push_back(InCall); }
std::vector<FCall*> GetCalls() const { return Calls; }
FMoney* GetAmount() const { return Amount; }
FDuration GetSeconds() const { return Seconds; }
FMoney* CalculateFee() const
{
FMoney* Result = const_cast<FMoney*>(FMoney::ZERO);
for (FCall* Call : Calls)
{
Result = Result->Plus(Amount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
return Result;
}
private:
FMoney* Amount;
FDuration Seconds;
std::vector<FCall*> Calls;
};
FPhone* Phone = new FPhone(FMoney::Wons(5), FDuration::OfSeconds(10));
Phone->Call(new FCall(FLocalDateTime(2018, 1, 1, 12, 10, 0), FLocalDateTime(2018, 1, 1, 12, 11, 0)));
Phone->Call(new FCall(FLocalDateTime(2018, 1, 2, 12, 10, 0), FLocalDateTime(2018, 1, 2, 12, 11, 0)));
FMoney* Fee = Phone->CalculateFee(); // FMoney::Wons(60)
class FNightlyDiscountPhone
{
public:
FNightlyDiscountPhone(FMoney* InNightlyAmount, FMoney* InRegularAmount, const FDuration& InSeconds)
: NightlyAmount(InNightlyAmount)
, RegularAmount(InRegularAmount)
, Seconds(InSeconds)
{
}
void Call(FCall* InCall) { Calls.push_back(InCall); }
std::vector<FCall*> GetCalls() const { return Calls; }
FMoney* GetAmount() const { return NightlyAmount; }
FDuration GetSeconds() const { return Seconds; }
FMoney* CalculateFee() const
{
FMoney* Result = const_cast<FMoney*>(FMoney::ZERO);
for (FCall* Call : Calls)
{
if (Call->GetFrom().GetHour() >= LATE_NIGHT_HOUR)
{
Result = Result->Plus(NightlyAmount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
else
{
Result = Result->Plus(RegularAmount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
}
return Result;
}
private:
constexpr int32_t LATE_NIGHT_HOUR = 22;
FMoney* NightlyAmount;
FMoney* RegularAmount;
FDuration Seconds;
std::vector<FCall*> Calls;
};
class FPhone
{
public:
FPhone(FMoney* InAmount, const FDuration& InSeconds, double InTaxRate)
: Amount(InAmount)
, Seconds(InSeconds)
, TaxRate(InTaxRate)
{}
void Call(FCall* InCall) { Calls.push_back(InCall); }
std::vector<FCall*> GetCalls() const { return Calls; }
FMoney* GetAmount() const { return Amount; }
FDuration GetSeconds() const { return Seconds; }
FMoney* CalculateFee() const
{
FMoney* Result = const_cast<FMoney*>(FMoney::ZERO);
for (FCall* Call : Calls)
{
Result = Result->Plus(Amount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
return Result->Plus(Result->Times(TaxRate));
}
private:
FMoney* Amount;
FDuration Seconds;
std::vector<FCall*> Calls;
double TaxRate;
};
class FNightlyDiscountPhone
{
public:
FNightlyDiscountPhone(FMoney* InNightlyAmount, FMoney* InRegularAmount, const FDuration& InSeconds, double InTaxRate)
: NightlyAmount(InNightlyAmount)
, RegularAmount(InRegularAmount)
, Seconds(InSeconds)
, TaxRate(InTaxRate)
{
}
void Call(FCall* InCall) { Calls.push_back(InCall); }
std::vector<FCall*> GetCalls() const { return Calls; }
FMoney* GetAmount() const { return NightlyAmount; }
FDuration GetSeconds() const { return Seconds; }
FMoney* CalculateFee() const
{
FMoney* Result = const_cast<FMoney*>(FMoney::ZERO);
for (FCall* Call : Calls)
{
if (Call->GetFrom().GetHour() >= LATE_NIGHT_HOUR)
{
Result = Result->Plus(NightlyAmount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
else
{
Result = Result->Plus(RegularAmount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
}
return Result->Plus(Result->Times(TaxRate));
}
private:
constexpr int32_t LATE_NIGHT_HOUR = 22;
FMoney* NightlyAmount;
FMoney* RegularAmount;
FDuration Seconds;
std::vector<FCall*> Calls;
double TaxRate;
};
class FPhone
{
using ThisClass = FPhone;
public:
enum class EPhoneType
{
Regular,
Nightly
};
FPhone(FMoney* InAmount, const FDuration& InSeconds, double InTaxRate)
: ThisClass(EPhoneType::Regular, InAmount, const_cast<FMoney*>(FMoney::ZERO), const_cast<FMoney*>(FMoney::ZERO), InSeconds)
{}
FPhone(FMoney* InNightlyAmount, FMoney* InRegularAmount, const FDuration& InSeconds)
: ThisClass(EPhoneType::Nightly, const_cast<FMoney*>(FMoney::ZERO), InNightlyAmount, InRegularAmount, InSeconds)
{}
FPhone(EPhoneType InType, FMoney* InAmount, FMoney* InNightlyAmount, FMoney* InRegularAmount, const FDuration& InSeconds)
: Type(InType)
, Amount(InAmount)
, NightlyAmount(InNightlyAmount)
, RegularAmount(InRegularAmount)
, Seconds(InSeconds)
{}
void Call(FCall* InCall) { Calls.push_back(InCall); }
std::vector<FCall*> GetCalls() const { return Calls; }
FMoney* GetAmount() const { return Amount; }
FDuration GetSeconds() const { return Seconds; }
FMoney* CalculateFee() const
{
FMoney* Result = const_cast<FMoney*>(FMoney::ZERO);
for (FCall* Call : Calls)
{
if (Type == EPhoneType::Regular)
{
Result = Result->Plus(Amount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
else
{
if (Call->GetFrom().GetHour() >= LATE_NIGHT_HOUR)
{
Result = Result->Plus(NightlyAmount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
else
{
Result = Result->Plus(RegularAmount->Times(Call->GetDuration().ToSeconds() / Seconds.ToSeconds()));
}
}
}
return Result;
}
private:
constexpr int32_t LATE_NIGHT_HOUR = 22;
EPhoneType Type;
FMoney* Amount;
FMoney* NightlyAmount;
FMoney* RegularAmount;
FDuration Seconds;
std::vector<FCall*> Calls;
};