Abstrakcyjna klasa bazowa powinna mieć lub nie mieć członków danych podczas używania wzorca dekoratora C ++

Niektóre posty wcześniej zadawały / dyskutowały, czy włączyć prywatne elementy danych do abstrakcyjnych klas bazowych. Chcę to zbadać na konkretnym przykładzie w połączeniu z wzorem dekoratora.

Natknąłem się na ten problem, kiedy wdrażałem bibliotekę Monte Carlo do wyceny finansowych instrumentów pochodnych. Generator losowych liczb normalnych jest istotną częścią biblioteki cenowej Monte Carlo. Masz kilka opcji, jak zdefiniować twoje zmienne normalne, zaczynając od generatora liczb losowych, np. można użyć metody Box-Muller lub odwrotnej skumulowanej funkcji normalnej, aby uzyskać zmienne normalne z jednolitych.

Chcesz publicznego interfejsu, który pozwala na losowe otrzymanie 1 lub więcej zmiennych losowych: np. getRandomNormal () i getRamdomNormals (). Weźmy więc abstrakcyjną klasę bazową RandomNormalGenerator. Chcesz przechowywać swoje losowe normalne w wektorze, ponieważ chcesz wykonać na nim pewne manipulacje w podklasach. Postanowiłem również zaimplementować próbkowanie antytetyczne, w którym biorę zapisane losowe normalne klasy wywodzące się z abstrakcyjnej bazy i odwracam znak tych losowych normalnych (zasada antytetycznego próbkowania). Mój plik nagłówkowy wyglądał tak

#ifndef RANDOMNORMALGENERATOR_H_
#define RANDOMNORMALGENERATOR_H_

#include "UniformBridge.h"
#include <memory>

class RandomNormalGenerator {
public:
    RandomNormalGenerator();
    RandomNormalGenerator(const UniformBridge& uniform_bridge);
    void SetSeed(long seed);

    virtual double getRandomNormal() = 0;
    virtual const std::vector<double>& getRandomNormals(size_t dimension);
protected:
    UniformBridge m_UBridge; // Need access to m_UBridge in derived classes.
    std::vector<double> m_Normals; //Need access to m_Normals in derived classes.
private:
};

class BoxMullerGenerator: public RandomNormalGenerator {
public:
    BoxMullerGenerator();
    BoxMullerGenerator(const UniformBridge& uniform_bridge);
    virtual double getRandomNormal();
protected:
private:
    double m_Cached_value;
    bool m_Cached_flag;
};

class AntitheticGenerator: public RandomNormalGenerator {
public:
    AntitheticGenerator(std::unique_ptr<RandomNormalGenerator> generator);
    virtual double getRandomNormal();

    // getRandomNormals will generate in first go, non-antithetic sampled samples,
    // when called for second time it will generate antithetic samples.
    virtual const std::vector<double>& getRandomNormals(size_t dimension);
protected:

private:
    AntitheticGenerator(const AntitheticGenerator&);
    AntitheticGenerator& operator=(const AntitheticGenerator&);

private:
    std::unique_ptr<RandomNormalGenerator> m_RandNormGenerator;
};

#endif /* RANDOMNORMALGENERATOR_H_ */

Zauważ, że AntitheticGenerator używa wzorca dekoratora dziedziczącego z abstrakcyjnej klasy bazowej i ma wskaźnik do tej abstrakcyjnej klasy bazowej (zrobi to również opakowanie wokół obiektu klasy bazowej).

Generator AntetheticGenerator weźmie wskaźnik np. do BoxMullera i wygeneruj losowe normalne przy użyciu BoxMullera, który użyje wtedy losowych normalnych (udekoruj je) przechowywanych w m_Normals z BoxMullera. Konkretnie odwróci znak tych wartości (jeśli w BoxMuller był wektor buforowany) i zapisał je na własnych m_Normals (m_Normals w AntitheticGenerator). Tutaj delegowanie wektora m_Normals do abstrakcyjnej klasy bazowej było bardzo przydatne, więc nie było potrzeby duplikowania w podklasach. Jednak mUBridge UniformBridge (most do jednolitego generatora losowego) w klasie bazowej nie był dobrym pomysłem. Generator AntitheticGenerator nie potrzebuje własnego, jednolitego generatora losowego, ponieważ użyje tego samego w BoxMuller ... i faktycznie mUbridge w generatorze antytetycznym nigdy nie jest używany.

Tak poprawiony kod powinien wyglądać.

#ifndef RANDOMNORMALGENERATOR_H_
#define RANDOMNORMALGENERATOR_H_

#include "UniformBridge.h"
#include <memory>

class RandomNormalGenerator {
public:
    RandomNormalGenerator();
    void SetSeed(long seed);

    virtual double getRandomNormal() = 0;
    virtual const std::vector<double>& getRandomNormals(size_t dimension);
protected:
    std::vector<double> m_Normals; //Need access to m_Normals in derived classes.
private:
};

class BoxMullerGenerator: public RandomNormalGenerator {
public:
    BoxMullerGenerator();
    BoxMullerGenerator(const UniformBridge& uniform_bridge);
    virtual double getRandomNormal();
protected:
private:
    double m_Cached_value;
    bool m_Cached_flag;
    UniformBridge m_UBridge;
};

class AntitheticGenerator: public RandomNormalGenerator {
public:
    AntitheticGenerator(std::unique_ptr<RandomNormalGenerator> generator);
    virtual double getRandomNormal();

    // getRandomNormals will generate in first go, non-antithetic sampled samples,
    // when called for second time it will generate antithetic samples.
    virtual const std::vector<double>& getRandomNormals(size_t dimension);
protected:

private:
    AntitheticGenerator(const AntitheticGenerator&);
    AntitheticGenerator& operator=(const AntitheticGenerator&);

private:
    std::unique_ptr<RandomNormalGenerator> m_RandNormGenerator;
};

#endif /* RANDOMNORMALGENERATOR_H_ */

Podsumowując, używając wzoru dekoratora do generowania losowych normalnych, warto zdefiniować przechowywanie normalnych w klasie bazowej, ale przechowywanie jednolitego generatora losowego powinno być delegowane do podklas (klasa dekorowana nie potrzebuje własnych).

questionAnswers(0)

yourAnswerToTheQuestion