how can this be refactored?
Improved application of Single Responsibility Principle, encapsulation, and domain modeling.
Start With Good Data Structures
public class StoreTimes {
public DayOfWeek Day {get; set;}
public string StartTime { get; set; }
public string EndTime { get; set; }
}
- It is clear that an "hours of operation" must consist of a day along with open and close times.
- So make a proper structure (class) that expresses this concept.
- A complete data structure tends to be very flexible. In our case it will solve the problem @mjolka pointed out.
- It simplifies the hell out of client code. i.e. dealing with "a list of key-value-pairs of days and store-times"
Ensure Objects Are Constructed Correctly
- Constructor parameters forces the client (code) to supply the required things.
- Arguments (the values passed via parameters) are easily validated up front before attempting to use bad or incomplete data.
.
public StoreTimes(DayOfWeek theDay, string startTime, string endTime)
{
Day = theDay;
StartTime = startTime ?? "0000";
EndTime = endTime ?? "0000";
}
Don't allow Client to Arbitrarily Change State
.
public class StoreTimes {
public DayOfWeek Day {get; protected set;}
public string StartTime { get; protected set; }
public string EndTime { get; protected set; }
Use Domain Language
Stores open and close, they do not start and stop.
public class StoreTimes {
public DayOfWeek Day {get; protected set;}
public string OpenTime { get; protected set; }
public string CloseTime { get; protected set; }
}
Make Cohesive Classes
OO programming is an exercise in self-reliance, for the classes. A class should know how to do things that is should be doing itself. The client should only have to tell to do it.
- At a restaurant you tell them to cook food, you don't do it for them.
- You ask to see a menu, you don't write a menu for them.
.
public class StoreTimes {
public string HoursOfOperation()
{
return String.Format("{0} : {1} to {2}", Day, OpenTime, CloseTime);
}
}
New Class Applying All the Points Above
public class HoursOfOperation
{
protected List<StoreTimes> TheHours { get; set; }
public HoursOfOperation()
{
TheHours = new List<StoreTimes>();
}
public void Add(StoreTimes newOpsHours)
{
if (newOpsHours == null) return;
TheHours.Add(newOpsHours);
}
public override string ToString()
{
StringBuilder me = new StringBuilder();
foreach (StoreTimes openTime in TheHours)
me.AppendLine(openTime.HoursOfOperation());
return me.ToString();
}
}
Lessons Learned Applied to Store Class
public class Store
{
protected int StoreID { get; set; }
protected string StoreName { get; set; }
protected HoursOfOperation OperatingHours { get; set; }
public Store(string storeName, HoursOfOperation operatingHours, int storeID ){
StoreID = storeID;
StoreName = storeName ?? "NoNameStore";
if (operatingHours == null)
throw new ArgumentNullException("Operating Hours is null");
OperatingHours = operatingHours;
}
public string HoursOfOperation()
{
return this.OperatingHours.ToString();
}
public override string ToString()
{
StringBuilder me = new StringBuilder();
me.AppendLine(string.Format("Store {0} ID {1}", StoreName, StoreID ));
me.AppendLine("Hours Of Operation:");
me.AppendLine(HoursOfOperation());
return me.ToString();
}
}
Client Code
static void Main(string[] args)
{
HoursOfOperation opsHours = new HoursOfOperation();
opsHours.Add(new StoreTimes(DayOfWeek.Monday, "0900", "1130"));
opsHours.Add(new StoreTimes(DayOfWeek.Monday, "1300", "1800"));
opsHours.Add(new StoreTimes(DayOfWeek.Saturday, "0800", "2100"));
opsHours.Add(new StoreTimes(DayOfWeek.Sunday, null, null));
Store CostingTons = new Store("CostingTons", opsHours, 1);
Console.WriteLine(CostingTons.ToString());
Console.ReadLine();
}