
C#初心者を卒業しよう(第4回)リファクタリングその1
はじめに
今回は、前回のサンプルプログラムをリファクタリングします。
マジックナンバーを取り除く
まずは、メートルをヤードに変換する定数を設定しましょう。
public class Const
{
public static readonly double METER_TO_YARD = 1.0936133d;
}
public class ToMeters : IDistance
{
private double _yards;
private double _meters;
public void Calculate(double yards)
{
_yards = yards;
_meters = yards / Const.METER_TO_YARD;
}
public string CreateAnswerMessage()
{
return $"{_yards} yards is {_meters} meters.";
}
}
同様に、ToYards メソッドにも定数を設定してください。
変換種別を指定する番号を enum にする
「メートル」を「ヤード」に変換するか、「ヤード」を「メートル」に変換するかの変換種別(convertNumber)を enum にします。
public enum ConvertNumber
{
ToYards = 1,
ToMeters = 2,
}
protected virtual ConvertNumber InputConvertNumber()
{
Console.WriteLine("Please input convert number.");
Console.WriteLine(
$"{(int)ConvertNumber.ToYards} : Convert meters to yards.");
Console.WriteLine(
$"{(int)ConvertNumber.ToMeters} : Convert yards to meters.");
if (Enum.TryParse(
typeof(ConvertNumber), Console.ReadLine(), out var convertNumber))
{
return (ConvertNumber)convertNumber;
}
throw new FormatException("Invalid input convert number.");
}
protected virtual IDistance? Create(ConvertNumber convertNumber)
{
switch (convertNumber)
{
case ConvertNumber.ToYards:
return (IDistance?)serviceProvider.GetService(typeof(IToYards));
case ConvertNumber.ToMeters:
return (IDistance?)serviceProvider.GetService(typeof(IToMeters));
default:
throw new ArgumentOutOfRangeException(
$"{convertNumber} is out of range.");
}
}
ソース全体
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services
.AddTransient<DistanceService>()
.AddScoped<IToYards, ToYards>()
.AddScoped<IToMeters, ToMeters>();
using IHost host = builder.Build();
var service = host.Services.GetService<DistanceService>() ??
throw new NotImplementedException(
"Faild to create 'DistanceService' object.");
service.Run();
public enum ConvertNumber
{
ToYards = 1,
ToMeters = 2,
}
public class DistanceService(IServiceProvider serviceProvider)
{
public void Run()
{
var convertNumber = InputConvertNumber();
var distanceObject = Create(convertNumber) ??
throw new NotImplementedException(
"Faild to create 'IDistance' object.");
var distance = InputDistance();
distanceObject.Calculate(distance);
OutputAnswer(distanceObject);
}
protected virtual ConvertNumber InputConvertNumber()
{
Console.WriteLine("Please input convert number.");
Console.WriteLine($"{(int)ConvertNumber.ToYards} : Convert meters to yards.");
Console.WriteLine($"{(int)ConvertNumber.ToMeters} : Convert yards to meters.");
if (Enum.TryParse(typeof(ConvertNumber), Console.ReadLine(), out var convertNumber))
{
return (ConvertNumber)convertNumber;
}
throw new FormatException("Invalid input convert number.");
}
protected virtual IDistance? Create(ConvertNumber convertNumber)
{
switch (convertNumber)
{
case ConvertNumber.ToYards:
return (IDistance?)serviceProvider.GetService(typeof(IToYards));
case ConvertNumber.ToMeters:
return (IDistance?)serviceProvider.GetService(typeof(IToMeters));
default:
throw new ArgumentOutOfRangeException(
$"{convertNumber} is out of range.");
}
}
protected virtual double InputDistance()
{
Console.WriteLine("Please input distance.");
if (double.TryParse(Console.ReadLine(), out var distance))
{
return distance;
}
throw new FormatException("Invalid input distance.");
}
protected virtual void OutputAnswer(IDistance distance)
{
var outputMessage = distance.CreateAnswerMessage();
Console.WriteLine(outputMessage);
}
}
public interface IDistance
{
void Calculate(double distance);
string CreateAnswerMessage();
}
public class Const
{
public static readonly double METER_TO_YARD = 1.0936133d;
}
public interface IToMeters : IDistance
{
}
public class ToMeters : IToMeters
{
private double _yards;
private double _meters;
public void Calculate(double yards)
{
_yards = yards;
_meters = yards / Const.METER_TO_YARD;
}
public string CreateAnswerMessage()
{
return $"{_yards} yards is {_meters} meters.";
}
}
public interface IToYards : IDistance
{
}
public class ToYards : IToYards
{
private double _yards;
private double _meters;
public void Calculate(double meters)
{
_meters = meters;
_yards = meters * Const.METER_TO_YARD;
}
public string CreateAnswerMessage()
{
return $"{_meters} meters is {_yards} yards.";
}
}
ダウンロード
ダウンロード用に置いてあるものは、クラスごとにファイルを分けてあります。
練習問題
より理解を深めるために、以下の練習問題に取り組んでみてください。
練習問題 04
今回の練習問題も、前回と全く同じです。
このサンプルプログラムに
「メートル」を「フィート」に、
「フィート」を「メートル」に
変換できる機能を追加してください。
機能を追加したら、前回の練習問題で作成したプログラムと比較してみてください。
おわりに
次回は、このサンプルをさらにリファクタリングします。お楽しみに。
いいなと思ったら応援しよう!
