Как избежать создания нескольких экземпляров объекта?

Заработная плата работника рассчитывается из двух элементов - 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 ответа

Решение

Я использую легкий вес модели. [Но это не может быть лучшим решением]

введите описание изображения здесь

РЕКОМЕНДАЦИИ

  1. Реализация шаблона Singleton в C# - Джон Скит также говорит о безопасности потоков.
  2. Почему практичный шаблон Flyweight?
  3. Шаблон дизайна мухи - 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 класс, который будет заполнен, если текущий объект не существует, и откуда объект будет извлечен, если он существует.

Другие вопросы по тегам