C++ - Filter pattern

C++ - Filter pattern
« kdy: 19. 12. 2020, 19:21:34 »
Ahojte kolegovia,

prichadzam si po radu ku skusenejsim :)
Riesim Filter pattern(?) ale zasekol som sa v navrhu:( tak prichadzam s prozbou
majme :
Kód: [Vybrat]
struct Item {
    int16_t     id;
};

class Rule{
    public:
        virtual ~Rule(){};
        virtual bool operator()(const Item & item) = 0;
};

class RuleLessThan: public Rule {
    private:
        int16_t id;
    public:
        RuleLessThan(int16_t iid): id(iid){}
        bool operator()(const Item & item){
            return item.id < id ? true : false;
        }
};

class RuleEqualTo: public Rule {
    private:
        int16_t id;
    public:
        RuleEqualTo(int16_t iid): id(iid){};
        bool operator()(const Item & item){
            return item.id == id ? true : false;
        };
};

class Filter {
    private:
        std::vector<Rule *> v_rule;
    public:
        Filter(){};
        ~Filter(){
            for(auto & rule : v_rule){
                delete rule;
            }
        };

        void add (Rule * rule){
            v_rule.push_back(rule);
        }

        bool apply(const Item & item ){
            for(auto & rule : v_rule){
                if((*rule)(item) == false){
                    return false;
                }
            }
            return true;
        }
};

int main(void){
    Item item_A = {15};
    Item item_B = {30};
    Item item_C = {40};

    Filter filter_A;
    Filter filter_B;

    filter_A.add(new RuleEqualTo(15));

    filter_B.add(new RuleEqualTo(30));
    filter_B.add(new RuleLessThan(50));


    if(filter_A.apply(item_A) == true){
        std::cout << "ok" << std::endl;
    }

    if(filter_B.apply(item_B) == true){
        std::cout << "ok" << std::endl;
    }

    if(filter_B.apply(item_C) == false){
        std::cout << "ok" << std::endl;
    }

    return 0;
}
majme vsak dalsi mozny vstup do rule a to:

Kód: [Vybrat]
struct Type {
    std::string type;
};

napada Vas, ako spravne zakompnovat "Type" do "Filter" a/alebo ako zakomponovat "Type" do "Filter" class?
Primarne ide o to, ze budem mat triedu Filter, ktora bude mat vo "Vector" n-Rules, ale tie by mali byt "Item" tak aj "Type"
Filter bude vediet pouzit .apply() podla typu--
Trocha som sa v navrhu zamotal tak hladam spravnu cestu

Diky
M.



Re:C++ - Filter pattern
« Odpověď #1 kdy: 19. 12. 2020, 20:06:07 »
Pokud chceš filtr, který se bude dynamicky rozhodovat podle více možných typů vstupu, tak můžeš použít třeba std::variant.

nula

Re:C++ - Filter pattern
« Odpověď #2 kdy: 20. 12. 2020, 08:22:30 »
Ahoj,
 uplne presne jsem nepochopil jak ten dotaz myslis, takze se jeste zeptam:

1) Chtel jsi rict, ze parametr funkce Filter.apply(X) muze byt ruzny? Jakoze to muze byt jak struct Item, tak std::string? Nejlepsi bude kdyz ukazes jak bys to chtel volat.

A pokud ad1) plati, pak:
a) Chces aplikovat vsechny Rule na vstupni hodnotu?
   - kazdy Rule se podle typu vstupu muze chovat jinak? Nebo respektive muze mit jiny kod?
   - nebo jen chces, aby Rule umel prijmout ruzne typy, ale v podstate prace s nima je vzdy stejna. Ma stejny kod?

b) Chces aby se aplikoval na dany parametr jen ty Rule tridy, ktere ho umi zpracovat? A ostatni ignorovat?


A jeste poznamka: omlouvam se, nechci byt uplne hnidopich, ale dve veci z toho kodu dost krici:
1) Potencialni bug. Ve svem kodu udelas toto:
Kód: [Vybrat]
filter_A.add(new RuleEqualTo(15));a ve funkci add() pak pridavas nove alokovany Rule do vektoru, ktery pak korektne cistis ve svem destruktoru. Nicmene pokud nekde predtim, nez do vektoru pomoci .push_back() ten pointer vlozis nastane vyjimka (treba v samotnem .push_back()), tak se novy Rule do toho vector<Rule> neprida a timpadem se pri jeho destrukci nebude ani deletovat a timpadem mas leak, protoze ti zustane viset v pameti az do konce behu programu. Dneska uz se operator new fakt neoplati skoro nikdy pouzivat. Kdyzuz pouzivas pointery, tak se koukni na smart pointers. V tomto pripade tedy std::unique_ptr a std::make_unique.

2) kdyz vracis bool hodnotu, tak tam staci podminka :) tedy misto:
Kód: [Vybrat]
return item.id == id ? true : false;staci napsat napriklad:
Kód: [Vybrat]
return item.id == id;

Re:C++ - Filter pattern
« Odpověď #3 kdy: 23. 12. 2020, 19:36:01 »
Pokud chceš filtr, který se bude dynamicky rozhodovat podle více možných typů vstupu, tak můžeš použít třeba std::variant.
Super, myslim ze toto by slo, o tej moznosti som ani netusil :)

Ahoj ahoj, totiz , ani ja som sa nevyjadril uplne presne :), nakoniec som musel cvhilku porozmyslat o navrhu a myslim ze to slo :)

Ano, ano, do prikladu som vrazil "new", nastastie bezne pouzivam smart pointre, ich vyhoda je nezrovnatelna :)
Povodny priklad som vyklepal do nasledujuceho tvaru, od zapudzrenia viacerych class (naprikald cez std::variant) do jedneho filtra som  upustil. Tak davam na inspiraciu/skomentovanie nasledujuceho kodu:
Kód: [Vybrat]
/* abstract rule template */
template <class T>
class TRule {
    public:
        virtual ~TRule(){};
        virtual bool operator()(const T & t) = 0;
};

template <typename T>
using RulePtr = std::unique_ptr<TRule<T>>;

template <typename T, typename Arg>
std::unique_ptr<T> Rule(Arg&& arg){
    return std::make_unique<T>(std::forward<Arg>(arg));
};

template <class T>
class TFilter {
    private:
        std::vector<RulePtr<T>> v_rule;
    public:
        TFilter(){};
        ~TFilter(){};

        void add(RulePtr<T> rule){
            v_rule.push_back(std::move(rule));
        }

        bool operator()(const T & t){
            for(auto & rule : v_rule){
                if((*rule)(t) == false){
                    return false;
                }
            }
            return true;
        }
};

/* Class */
struct Item {
    int16_t     id;
};

namespace ItemRule {

    class LessThan: public TRule<Item> {
        private:
            int16_t id;
        public:
            ~LessThan(){};
            LessThan(int16_t iid): id(iid){};
            bool operator()(const Item & item) override{
                return item.id < id ? true : false;
            }
    };

    class EqualTo: public TRule<Item>  {
        private:
            int16_t id;
        public:
            ~EqualTo(){};
            EqualTo(int16_t iid): id(iid){};
            bool operator()(const Item & item) override{
                return item.id == id ? true : false;
            };
    };
};

class ItemFilter : public TFilter<Item>{};

int main(void){

    /* test A */
    Item item_A = {15};

    ItemFilter itemfilter;
    itemfilter.add(std::make_unique<ItemRule::EqualTo>(15));   // (1)
    itemfilter.add(Rule<ItemRule::LessThan>(20));              // (1) 

    // (1) equivalent

    if(itemfilter(item_A) == true){
        std::cout << "ok" << std::endl;
    }else{
       std::cout << "off" << std::endl;
    }

    return 0;
}