Как избежать создания нескольких экземпляров объекта?
Заработная плата работника рассчитывается из двух элементов - Basic
а также StandardPoint
, Один сотрудник будет получать один базовый и один или несколько (или нет) StandardPoint каждый месяц.
Существуют различные стандартные точки, а именно - StarPerformerPoint, RecognitionPoint, ReferralPoint, BrandingPoint.
Существует функциональность для расчета TotalAnnualSalary. В течение года сотрудник имеет право использовать максимум 4 стандартных балла. Даже если он наберет больше очков, только 4 будут рассчитаны для расчета общего годового оклада.
У меня есть следующий код. Работает нормально. Однако есть неэффективное использование памяти. StandardPointElement создается несколько раз.
Как мы можем оптимизировать создание объекта в этом сценарии?
ОБНОВИТЬ
Можем ли мы использовать что-то вроде рисунка в полулегком весе?
Википедия говорит о шаблоне Flyweight
Flyweight - это объект, который минимизирует использование памяти, делясь как можно большим количеством данных с другими подобными объектами; это способ использовать объекты в большом количестве, когда простое повторное представление будет использовать недопустимый объем памяти.
В статье " Шаблон дизайна Flyweight - C#" Шайлендра Чаухан упоминает следующее
Внешние данные вычисляются на лету средствами во время выполнения, и они хранятся за пределами объекта с навесным весом. Следовательно это может быть с состоянием.
Почему практичный шаблон Flyweight?
Код
interface ISalaryScoreElement
{
int SalaryScore { get; }
}
public class BasicElement : ISalaryScoreElement
{
public int SalaryScore
{
get
{
return 100;
}
}
}
public class StandardPointElement : ISalaryScoreElement
{
public int SalaryScore
{
get
{
return 10;
}
}
}
Класс сотрудника
class Employee
{
private List<string> eligibility;
public List<string> EligibleSalaryTypes
{
get
{
return eligibility;
}
}
public Employee(List<string> eligibility)
{
this.eligibility = eligibility;
}
public int GetTotalAnnualSalary()
{
int totalSalary = 0;
ISalaryScoreElement sal = null;
CalculatorFactory factory = new CalculatorFactory();
int occurenceCountForStandardPoint = 0;
foreach (string salaryType in EligibleSalaryTypes)
{
switch (salaryType)
{
case "Basic":
sal = factory.GetSalaryElement("BasicElement");
break;
case "ReferralPoint":
sal = factory.GetSalaryElement("StandardPointElement");
break;
case "BrandingPoint":
sal = factory.GetSalaryElement("StandardPointElement");
break;
case "RecognitionPoint":
sal = factory.GetSalaryElement("StandardPointElement");
break;
case "StarPerformerPoint":
sal = factory.GetSalaryElement("StandardPointElement");
break;
default:
throw new Exception("No mapping available");
}
if (sal is StandardPointElement)
{
occurenceCountForStandardPoint++;
if (occurenceCountForStandardPoint > 4)
{
//StandardPointElement can be considered a maximum of 4 times for salary calculation
continue;
}
}
totalSalary = totalSalary + sal.SalaryScore;
}
return totalSalary;
}
}
завод
class CalculatorFactory
{
public ISalaryScoreElement GetSalaryElement(string salaryKey)
{
ISalaryScoreElement c = null;
switch (salaryKey)
{
case "BasicElement":
c = new BasicElement();
break;
case "StandardPointElement":
c = new StandardPointElement();
break;
default:
throw new Exception("Factory cannot create the object specified");
}
return c;
}
}
клиент
class Program
{
static void Main(string[] args)
{
List<string> eligibleBonus = new List<string>();
//For January 2013
eligibleBonus.Add("Basic");
eligibleBonus.Add("StarPerformerPoint");
//For February 2013
eligibleBonus.Add("Basic");
eligibleBonus.Add("StarPerformerPoint");
eligibleBonus.Add("ReferralPoint");
//For March 2013
eligibleBonus.Add("Basic");
eligibleBonus.Add("BrandingPoint");
eligibleBonus.Add("RecognitionPoint");
//For April 2013
eligibleBonus.Add("Basic");
eligibleBonus.Add("BrandingPoint");
Employee e = new Employee(eligibleBonus);
int effectiveSalary = e.GetTotalAnnualSalary();
Console.WriteLine(effectiveSalary);
Console.ReadKey();
}
}
4 ответа
Я использую легкий вес модели. [Но это не может быть лучшим решением]
РЕКОМЕНДАЦИИ
- Реализация шаблона Singleton в C# - Джон Скит также говорит о безопасности потоков.
- Почему практичный шаблон Flyweight?
- Шаблон дизайна мухи - C#
Фабрика легковесов
class CalculatorFlyweightFactory
{
Dictionary<string, ISalaryScoreElement> calculators = new Dictionary<string, ISalaryScoreElement>();
public int TotalObjectsCreated
{
get { return calculators.Count; }
}
public ISalaryScoreElement GetSalaryElement(string salaryKey)
{
ISalaryScoreElement c = null;
if (calculators.ContainsKey(salaryKey))
{
c = calculators[salaryKey];
}
else
{
switch (salaryKey)
{
case "BasicElement":
c = new BasicElement();
calculators.Add("BasicElement", c);
break;
case "StandardPointElement":
c = new StandardPointElement();
calculators.Add("StandardPointElement", c);
break;
default:
throw new Exception("Factory cannot create the object specified");
}
}
return c;
}
}
грузиков
interface ISalaryScoreElement
{
int SalaryScore { get; }
//Newly Added
int OccurenceCount { get; set; }
}
public class BasicElement : ISalaryScoreElement
{
public int SalaryScore
{
get
{
return 100;
}
}
public int OccurenceCount { get; set; }
}
public class StandardPointElement : ISalaryScoreElement
{
public int SalaryScore
{
get
{
return 10;
}
}
public int OccurenceCount { get; set; }
}
функция
public int GetTotalAnnualSalary()
{
int totalSalary = 0;
ISalaryScoreElement sal = null;
CalculatorFlyweightFactory flyweightFactory = new CalculatorFlyweightFactory();
foreach (string salaryType in EligibleSalaryTypes)
{
switch (salaryType)
{
case "Basic":
sal = flyweightFactory.GetSalaryElement("BasicElement");
break;
case "ReferralPoint":
sal = flyweightFactory.GetSalaryElement("StandardPointElement");
break;
case "BrandingPoint":
sal = flyweightFactory.GetSalaryElement("StandardPointElement");
break;
case "RecognitionPoint":
sal = flyweightFactory.GetSalaryElement("StandardPointElement");
break;
case "StarPerformerPoint":
sal = flyweightFactory.GetSalaryElement("StandardPointElement");
break;
default:
throw new Exception("No mapping available");
}
if (sal is StandardPointElement && sal.OccurenceCount >= 4)
{
//StandardPointElement can be considered a maximum of 2 times for salary calculation
continue;
}
sal.OccurenceCount = sal.OccurenceCount + 1;
totalSalary = totalSalary + sal.SalaryScore;
}
return totalSalary;
}
Похоже, вы хотите использовать шаблон синглтона для StandardPointElement
, Для этого создайте статическое поле для хранения одного значения. Потребители будут использовать это значение вместо указания new StandardElementPoint()
, Также я сделал конструктор protected
чтобы потребители не могли случайно создать новые ценности
public class StandardPointElement : ISalaryScoreElement
{
public static readonly StandardPointElement Instance =
new StandardPointElement();
protected StandardPointElement() { }
public int SalaryScore
{
get
{
return 10;
}
}
}
Новый конвертировать все виды использования new StandardElementPoint
в вашем коде StandardElementPoint.Instance
У вас действительно не хватает памяти, или что-то?
В любом случае, вы всегда можете реализовать шаблон Singleton для классов, которые вы хотите создать только один раз. Лучшее обсуждение того, как реализовать, - это Джон Скит: http://csharpindepth.com/Articles/General/Singleton.aspx
Позвоните обоим factory.GetSalaryElement("BasicElement");
а также factory.GetSalaryElement("StandardPointElement");
только один раз, до начала цикла, и повторно использовать объекты в цикле.
Или, если вам действительно нечего делать, используйте один внутренний словарь Dictionary<string, ISalaryScoreElement>
как поле CalculatorFactory
класс, который будет заполнен, если текущий объект не существует, и откуда объект будет извлечен, если он существует.