如何避免创建多个对象实例?

时间:2014-02-06 14:38:04

标签: c# oop design-patterns flyweight-pattern

员工的工资是根据两个要素计算的 - BasicStandardPoint。一名员工每月将获得一个Basic和一个或多个(或没有)StandardPoint。

有各种StandardPoints,即StarPerformerPoint,RecognitionPoint,ReferralPoint,BrandingPoint。

有一项功能可以计算TotalAnnualSalary。在一年内,员工有资格获得最多4个标准点。即使他获得更多积分,也只计算4年总薪水计算。

我有以下代码。它工作正常。但是,存在无效的内存利用率。 StandardPointElement已多次创建。

我们如何在这种情况下优化对象创建?

更新

我们可以使用像flyweight模式这样的东西吗?

维基百科说Flyweight pattern

  

flyweight是一个通过与其他类似对象共享尽可能多的数据来最小化内存使用的对象;当一个简单的重复表示会使用不可接受的内存量时,它是一种大量使用对象的方法。

在文章Flyweight Design Pattern - C#中,Shailendra Chauhan提到了以下内容

  

外部数据是在运行时在飞行中计算的,它保存在flyweight对象之外。因此它可以是有状态的。

Why is the Flyweight Pattern practical?

代码

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 个答案:

答案 0 :(得分:1)

在循环开始之前,只调用factory.GetSalaryElement("BasicElement");factory.GetSalaryElement("StandardPointElement");一次,然后重复使用循环中的对象。

或者,如果您真的没有更好的事情要做,请将一个内部字典Dictionary<string, ISalaryScoreElement>作为CalculatorFactory类的字段,如果当前对象不存在,将填充该字段,以及该对象将从何处填充如果确实存在则被检索。

答案 1 :(得分:1)

你实际上是在耗尽内存吗?

无论如何,您始终可以为您只想创建一次的类实现Singleton pattern。关于如何实施的最佳讨论是由Jon Skeet撰写的:http://csharpindepth.com/Articles/General/Singleton.aspx

答案 2 :(得分:1)

听起来你想使用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

答案 3 :(得分:0)

我正在使用flyweight模式。 [但这可能不是最好的解决方案]

enter image description here

<强>参考

  1. Implementing the Singleton Pattern in C# - Jon Skeet也讨论了线程安全问题。
  2. Why is the Flyweight Pattern practical?
  3. Flyweight Design Pattern - C#
  4. Flyweight Factory

    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;
        }