web-dev-qa-db-fra.com

Doit-on rendre la base de données appelle dans le constructeur ou la méthode d'une classe?

Prenez l'instance suivante par exemple: CreditCardApplication classe

 public class CreditCardApplication
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
        public decimal GrossAnnualIncome { get; set; }
        public string FrequentFlyerNumber { get; set; } 
    }

Et il y a un CreditCardApplicationvaluator classe

public class CreditCardApplicationEvaluator
    {
        private const int AutoReferralMaxAge = 20;
        private const int HighIncomeThreshhold = 100_000;
        private const int LowIncomeThreshhold = 20_000;

        public CreditCardApplicationDecision Evaluate(CreditCardApplication application)
        {
            if (application.GrossAnnualIncome >= HighIncomeThreshhold)
            {
                return CreditCardApplicationDecision.AutoAccepted;
            }

            if (application.Age <= AutoReferralMaxAge)
            {
                return CreditCardApplicationDecision.ReferredToHuman;
            }

            if (application.GrossAnnualIncome < LowIncomeThreshhold)
            {
                return CreditCardApplicationDecision.AutoDeclined;
            }

            return CreditCardApplicationDecision.ReferredToHuman;
        }       
    }

CreditCardApplicationDecision est une énumération.

Maintenant, comme vous pouvez le constater, il existe un certain Const privé défini à l'intérieur CreditCardApplicationvaluator classe. Dans une application réelle mondiale, ces valeurs proviendront probablement d'une base de données.

La question est donc où est-ce que je fais que la base de données appelle à la base de données pour définir ces constantes? À l'intérieur du constructeur? Ou dans Evaluate méthode?

Devrais-je créer une autre classe Thresholds avec les propriétés telles que AutoReferralMaxAgeetC et transmettez-la sur Evaluate méthode comme suit:

static void Main(string[] args)
{
   //CreditCardApplication instance creation code goes here... 

   Thresholds thresholds =new Thresholds();
   thresholds = _unitOfWork.CreditcardRepository.GetThresholds();
   CreditCardApplicationEvaluator eval=new CreditCardApplicationEvaluator();
  var decision = eval.Evaluate(creditCardApplication,thresholds);
}

Ou devrais-je simplement placer unitOfWork.CreditcardRepository.GetThresholds() Inside Evaluate méthode de CreditCardApplicationvaluator classe, ou peut-être son constructeur?


L'appel de la base de données à l'intérieur d'un constructeur est probablement une mauvaise idée, comme indiqué par @greg. Alors maintenant ce qui reste sans réponse est que dois-je:

  1. Avoir UNITOFWORK.CREDITCARDCARDREPOSITORY.GETTHRESHOLDS () INTÉRIEUR MAIN ()
  2. ou dans l'évaluation () méthode de CreditCardApplicationvaluator classe
4
SamuraiJack

Les constructeurs ne doivent pas faire du travail. L'initialisation d'un nouvel objet devrait se produire très rapidement et faire des appels de base de données ou interagir avec toute ressource en dehors du processus actuel, peut prendre considérablement plus longtemps.

Au lieu de cela, votre constructeur devrait soit exiger les données de la base de données comme arguments distincts, de sorte que les appels de base de données sont effectués avant de créer le nouvel objet ou de déplacer cette logique dans une méthode d'instance.

Les constructeurs doivent être limités à l'affectation de la nouvelle mémoire pour le nouvel objet (comme initialisation des collections vides ou d'attribuer des valeurs par défaut aux champs obligatoires) et en veillant à ce que l'objet soit dans un état valide lors de la première création de la première fois.

Tout ce qui est au-delà appartient dans une méthode d'instance ou des arguments passés dans le constructeur.

Pour être spécifique à votre cas d'utilisation, les trois entiers "Cons" devraient être des arguments au constructeur. En outre, le seuil de revenu est en réalité un bon candidat pour une nouvelle classe, car vous ne voulez pas un seuil élevé de 20 000 et un seuil bas de 100 000.

public class IncomeThreshhold
{
    public int Low { get; }
    public int High { get; }

    public IncomeThreshhold(int low, int high)
    {
        if (low < 0)
            throw new ArgumentOutOfRangeException();

        if (high < 0)
            throw new ArgumentOutOfRangeException();

        if (high < low)
            throw new ArgumentOutOfRangeException();

        Low = low;
        High = high;
    }
}

Ensuite, votre classe CreditCardApplicationValuator devient un peu plus facile à construire avec des données valides:

public class CreditCardApplicationEvaluator
{
    private int AutoReferralMaxAge { get; }
    private IncomeThreshhold IncomeThreshhold { get; }

    public CreditCardApplicationEvaluator(int autoReferralMaxAge, IncomeThreshhold incomeThreshhold)
    {
        if (autoReferralMaxAge < someValueProbablyDrivenByRegulations)
            throw new ArgumentOutOfRangeException();

        AutoReferralMaxAge = autoReferralMaxAge;
        IncomeThreshhold = incomeThreshhold;
    }

    public CreditCardApplicationDecision Evaluate(CreditCardApplication application)
    {
        if (application.GrossAnnualIncome >= IncomeThreshhold.High)
        {
            return CreditCardApplicationDecision.AutoAccepted;
        }

        if (application.Age <= AutoReferralMaxAge)
        {
            return CreditCardApplicationDecision.ReferredToHuman;
        }

        if (application.GrossAnnualIncome < IncomeThreshhold.Low)
        {
            return CreditCardApplicationDecision.AutoDeclined;
        }

        return CreditCardApplicationDecision.ReferredToHuman;
    }
}

L'initialisation de ces objets en conjonction avec une unité de travail ou de référentiel se termine comme ceci:

static void Main(string[] args)
{
    var incomeThreshhold = unitOfWork.CreditcardRepository.GetThreshold(...);
    var autoReferralMaxAge = unitOfWork.CreditcardRepository.GetAutoReferralMaxAge(...);
    var evaluator = new CreditCardApplicationEvaluator(autoReferralMaxAge, incomeThreshhold);
    var application  unitOfWork.CreditcardRepository.GetApplication(...);
    var decision = evaluator.Evaluate(application);
}
7
Greg Burghardt