2017-02-11 2 views
1

Was ich suche ist, nicht fließend Klasse mit:Was sind ein guter Weg, um nicht-fließende Schnittstelle als fließend zu "re-implementieren"?

class NonFluent { 
    int i=0; 
public: 
    void setValue(int i) {this->i = i;} 
    void multiplyValue(int i) {this->i *= i;} 
    int getValue() {return this->i;} 
}; 

Ich mag würde void Methoden ändern, um tatsächlich Bezug auf *this zurückzukehren. Ich weiß, dass es unmöglich ist, nur abzuleiten, weil wir nicht nur einen Rückgabetyp ändern können, weil C++ Funktionsaufrufe nicht unterscheiden kann.

Wir konnten Zusammensetzung verwenden:

class Fluent { 
    Fluent& setValue(int i) {var.setValue(i); return *this;} 
    Fluent& multiplyValue(int i) {var.multiplyValue(i); return *this;} 
    int getValue() {return var.getValue();} 

private: 
    NonFluent var; 
}; 

Aber das ist ein Schmerz, wenn es viele void Methoden zu beginnen. Wir könnten auch Objekt-Editor verwenden, fragte ich Frage: Is Object Editor a good approach if there are multiple member functions to call?, aber es hat viele Nachteile.

Kennen Sie irgendwelche guten Methoden, dies zu tun? (Ohne Änderung nicht fließend Klasse direkt?)

Antwort

0

Als eine andere Antwort, nahm ich anderen Ansatz, dass die Ergebnisse in niedrigsten Code Zusatz:

Editor:

template <class T> 
struct EditorImpl 
{ 
    T* ptr; 

    template <class F> 
    EditorImpl& operator()(F&& f) 
    { 
     f(ptr); 
     return *this; 
    } 

    T* yield() const { 
     return ptr; 
    } 
}; 

template <class T> 
EditorImpl<T> Editor(T* ptr) { return EditorImpl<T>{ptr}; } 

template <class T> 
EditorImpl<T> Editor(T& ref) { return EditorImpl<T>{&ref}; } 

GET_MACRO (alles ist bis zu 100):

namespace detail { 
#define GET_MACRO_1(_1, NAME, ...) NAME 
#define GET_MACRO_2(_1, _2, NAME, ...) NAME 
#define GET_MACRO_3(_1, _2, _3, NAME, ...) NAME 
//... 
#define GET_MACRO_98(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, NAME, ...) NAME 
#define GET_MACRO_99(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, NAME, ...) NAME 
#define GET_MACRO_100(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100, NAME, ...) NAME 
} 

-Makro, erzeugt Lambda, die auf dem Objekt Makro-Argument aufruft:

namespace detail { 
#define E_1(_1)[](auto* p) {p -> _1; } 
#define E_2(_1,_2)[](auto* p) {p -> _1; p -> _2; } 
#define E_3(_1,_2,_3)[](auto* p) {p -> _1; p -> _2; p -> _3; } 
//...  
#define E_98(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98)[](auto* p) {p -> _1; p -> _2; p -> _3; p -> _4; p -> _5; p -> _6; p -> _7; p -> _8; p -> _9; p -> _10; p -> _11; p -> _12; p -> _13; p -> _14; p -> _15; p -> _16; p -> _17; p -> _18; p -> _19; p -> _20; p -> _21; p -> _22; p -> _23; p -> _24; p -> _25; p -> _26; p -> _27; p -> _28; p -> _29; p -> _30; p -> _31; p -> _32; p -> _33; p -> _34; p -> _35; p -> _36; p -> _37; p -> _38; p -> _39; p -> _40; p -> _41; p -> _42; p -> _43; p -> _44; p -> _45; p -> _46; p -> _47; p -> _48; p -> _49; p -> _50; p -> _51; p -> _52; p -> _53; p -> _54; p -> _55; p -> _56; p -> _57; p -> _58; p -> _59; p -> _60; p -> _61; p -> _62; p -> _63; p -> _64; p -> _65; p -> _66; p -> _67; p -> _68; p -> _69; p -> _70; p -> _71; p -> _72; p -> _73; p -> _74; p -> _75; p -> _76; p -> _77; p -> _78; p -> _79; p -> _80; p -> _81; p -> _82; p -> _83; p -> _84; p -> _85; p -> _86; p -> _87; p -> _88; p -> _89; p -> _90; p -> _91; p -> _92; p -> _93; p -> _94; p -> _95; p -> _96; p -> _97; p -> _98; } 
#define E_99(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99)[](auto* p) {p -> _1; p -> _2; p -> _3; p -> _4; p -> _5; p -> _6; p -> _7; p -> _8; p -> _9; p -> _10; p -> _11; p -> _12; p -> _13; p -> _14; p -> _15; p -> _16; p -> _17; p -> _18; p -> _19; p -> _20; p -> _21; p -> _22; p -> _23; p -> _24; p -> _25; p -> _26; p -> _27; p -> _28; p -> _29; p -> _30; p -> _31; p -> _32; p -> _33; p -> _34; p -> _35; p -> _36; p -> _37; p -> _38; p -> _39; p -> _40; p -> _41; p -> _42; p -> _43; p -> _44; p -> _45; p -> _46; p -> _47; p -> _48; p -> _49; p -> _50; p -> _51; p -> _52; p -> _53; p -> _54; p -> _55; p -> _56; p -> _57; p -> _58; p -> _59; p -> _60; p -> _61; p -> _62; p -> _63; p -> _64; p -> _65; p -> _66; p -> _67; p -> _68; p -> _69; p -> _70; p -> _71; p -> _72; p -> _73; p -> _74; p -> _75; p -> _76; p -> _77; p -> _78; p -> _79; p -> _80; p -> _81; p -> _82; p -> _83; p -> _84; p -> _85; p -> _86; p -> _87; p -> _88; p -> _89; p -> _90; p -> _91; p -> _92; p -> _93; p -> _94; p -> _95; p -> _96; p -> _97; p -> _98; p -> _99; } 
#define E_100(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100)[](auto* p) {p -> _1; p -> _2; p -> _3; p -> _4; p -> _5; p -> _6; p -> _7; p -> _8; p -> _9; p -> _10; p -> _11; p -> _12; p -> _13; p -> _14; p -> _15; p -> _16; p -> _17; p -> _18; p -> _19; p -> _20; p -> _21; p -> _22; p -> _23; p -> _24; p -> _25; p -> _26; p -> _27; p -> _28; p -> _29; p -> _30; p -> _31; p -> _32; p -> _33; p -> _34; p -> _35; p -> _36; p -> _37; p -> _38; p -> _39; p -> _40; p -> _41; p -> _42; p -> _43; p -> _44; p -> _45; p -> _46; p -> _47; p -> _48; p -> _49; p -> _50; p -> _51; p -> _52; p -> _53; p -> _54; p -> _55; p -> _56; p -> _57; p -> _58; p -> _59; p -> _60; p -> _61; p -> _62; p -> _63; p -> _64; p -> _65; p -> _66; p -> _67; p -> _68; p -> _69; p -> _70; p -> _71; p -> _72; p -> _73; p -> _74; p -> _75; p -> _76; p -> _77; p -> _78; p -> _79; p -> _80; p -> _81; p -> _82; p -> _83; p -> _84; p -> _85; p -> _86; p -> _87; p -> _88; p -> _89; p -> _90; p -> _91; p -> _92; p -> _93; p -> _94; p -> _95; p -> _96; p -> _97; p -> _98; p -> _99; p -> _100; } 
} 

#define E_(...) GET_MACRO_100(__VA_ARGS__, E_100, E_99, E_98, E_97, E_96, E_95, E_94, E_93, E_92, E_91, E_90, E_89, E_88, E_87, E_86, E_85, E_84, E_83, E_82, E_81, E_80, E_79, E_78, E_77, E_76, E_75, E_74, E_73, E_72, E_71, E_70, E_69, E_68, E_67, E_66, E_65, E_64, E_63, E_62, E_61, E_60, E_59, E_58, E_57, E_56, E_55, E_54, E_53, E_52, E_51, E_50, E_49, E_48, E_47, E_46, E_45, E_44, E_43, E_42, E_41, E_40, E_39, E_38, E_37, E_36, E_35, E_34, E_33, E_32, E_31, E_30, E_29, E_28, E_27, E_26, E_25, E_24, E_23, E_22, E_21, E_20, E_19, E_18, E_17, E_16, E_15, E_14, E_13, E_12, E_11, E_10, E_9, E_8, E_7, E_6, E_5, E_4, E_3, E_2, E_1)(__VA_ARGS__) 

Finale Makro:

namespace detail { 
#define EDIT_0(_1)Editor(_1).yield() 
#define EDIT_1(_1,_2)Editor(_1)(E_(_2)).yield() 
#define EDIT_2(_1,_2,_3)Editor(_1)(E_(_2,_3)).yield() 
#define EDIT_3(_1,_2,_3,_4)Editor(_1)(E_(_2,_3,_4)).yield() 
//... 
#define EDIT_98(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99)Editor(_1)(E_(_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99)).yield() 
#define EDIT_99(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100)Editor(_1)(E_(_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,_61,_62,_63,_64,_65,_66,_67,_68,_69,_70,_71,_72,_73,_74,_75,_76,_77,_78,_79,_80,_81,_82,_83,_84,_85,_86,_87,_88,_89,_90,_91,_92,_93,_94,_95,_96,_97,_98,_99,_100)).yield() 
} 
#define EDIT(...) GET_MACRO_100(__VA_ARGS__, EDIT_99, EDIT_98, EDIT_97, EDIT_96, EDIT_95, EDIT_94, EDIT_93, EDIT_92, EDIT_91, EDIT_90, EDIT_89, EDIT_88, EDIT_87, EDIT_86, EDIT_85, EDIT_84, EDIT_83, EDIT_82, EDIT_81, EDIT_80, EDIT_79, EDIT_78, EDIT_77, EDIT_76, EDIT_75, EDIT_74, EDIT_73, EDIT_72, EDIT_71, EDIT_70, EDIT_69, EDIT_68, EDIT_67, EDIT_66, EDIT_65, EDIT_64, EDIT_63, EDIT_62, EDIT_61, EDIT_60, EDIT_59, EDIT_58, EDIT_57, EDIT_56, EDIT_55, EDIT_54, EDIT_53, EDIT_52, EDIT_51, EDIT_50, EDIT_49, EDIT_48, EDIT_47, EDIT_46, EDIT_45, EDIT_44, EDIT_43, EDIT_42, EDIT_41, EDIT_40, EDIT_39, EDIT_38, EDIT_37, EDIT_36, EDIT_35, EDIT_34, EDIT_33, EDIT_32, EDIT_31, EDIT_30, EDIT_29, EDIT_28, EDIT_27, EDIT_26, EDIT_25, EDIT_24, EDIT_23, EDIT_22, EDIT_21, EDIT_20, EDIT_19, EDIT_18, EDIT_17, EDIT_16, EDIT_15, EDIT_14, EDIT_13, EDIT_12, EDIT_11, EDIT_10, EDIT_9, EDIT_8, EDIT_7, EDIT_6, EDIT_5, EDIT_4, EDIT_3, EDIT_2, EDIT_1, EDIT_0)(__VA_ARGS__) 

Beispiel Klasse:

class Simple { 
    int i=0; 
public: 
    Simple() : Simple(0) {} 
    Simple(int i) {this->i = i;} 
    void setValue(int i) {this->i = i;} 
    void multiplyValue(int i) {this->i *= i;} 
    void halve() {this->i /= 2;} 
    int getValue() {return this->i;} 

}; 

Und nach all dem Wahnsinn, der Nutzung:

Simple* simple = EDIT(new Simple, setValue(50), multiplyValue(3)); 

Das ist das Beste, was ich könnte tun :)

2

Ein besserer Ansatz, dass Sie mit Fluent nutzen könnten, aber nicht mit NonFluent, ist Ihre Klasse unveränderlich zu machen, und haben ihre Methoden, um neue Objekte mit den Ergebnissen der Änderung zurückgeben :

class Fluent { 
    static Fluent withValue(int i) { 
     NonFluent v; 
     v.setValue(i); 
     return Fluent(v); 
    } 
    Fluent multiplyValue(int i) const { 
     Fluent res(var); 
     res.var.multiplyValue(i); 
     return res; 
    } 
    int getValue() const {return var.getValue;} 
private: 
    Fluent(const NonFluent& v) : var(v) {} 
    NonFluent var; 
}; 

Beachten Sie die statische Factory-Methode erstellen Fluent Objekte.

Der Code der Fabrik unter Verwendung sieht wie folgt aus:

int res = Fluent 
    .withValue(5) 
    .multiplyValue(2) 
    .getValue(); 

Dies gibt Ihnen die Möglichkeit, die API zu überarbeiten anderen fließfähigen Objekten umfassen Verfahren unter, wie folgt aus:

Fluent multiply(const Fluent& other) const { 
    Fluent res(var); 
    res.var.multiplyValue(other.getValue()); 
    return res; 
} 

Das Gesamtergebnis ist, dass Ihre API gleichzeigig wird, ohne etwas in der ursprünglichen API zu ändern.

1

Ich dachte eine Weile darüber nach, und ich konnte eine bequeme Syntax für den Vererbungsansatz erstellen, wobei fließende Methoden mit f_ beginnen. Hier

ist einige Makro Magie:

#define FIFTHS(_1, _2, _3, _4, _5, NAME, ...) NAME 
#define MODIFY_ARGS_1(_1_) _1_ _1 
#define MODIFY_ARGS_2(_1_, _2_) _1_ _1, _2_ _2 
#define MODIFY_ARGS_3(_1_, _2_, _3_) _1_ _1, _2_ _2, _3_ _3 
#define MODIFY_ARGS_4(_1_, _2_, _3_, _4_) _1_ _1, _2_ _2, _3_ _3, _4_ _4 
#define MODIFY_ARGS_5(_1_, _2_, _3_, _4_, _5_) _1_ _1, _2_ _2, _3_ _3, _4_ _4, _5_ _5 
#define MODIFY_ARGS(...) FIFTHS(__VA_ARGS__, MODIFY_ARGS_5, MODIFY_ARGS_4, MODIFY_ARGS_3, MODIFY_ARGS_2, MODIFY_ARGS_1)(__VA_ARGS__) 

#define SEQUENCE_1(_1_) _1 
#define SEQUENCE_2(_1_, _2_) _1, _2 
#define SEQUENCE_3(_1_, _2_, _3_) _1, _2, _3 
#define SEQUENCE_4(_1_, _2_, _3_, _4_) _1, _2, _3, _4 
#define SEQUENCE_5(_1_, _2_, _3_, _4_, _5_) _1, _2, _3, _4, _5 
#define SEQUENCE(...) FIFTHS(__VA_ARGS__, SEQUENCE_5, SEQUENCE_4, SEQUENCE_3, SEQUENCE_2, SEQUENCE_1)(__VA_ARGS__) 

#define FLUENTIZE_DERIVE() CONCATENATE(Fluent,CURRENT_BASE) : public CURRENT_BASE 
#define FLUENTIZE_METHOD(name, ...) CONCATENATE(Fluent,CURRENT_BASE)& f_ ## name (MODIFY_ARGS(__VA_ARGS__)) {name(SEQUENCE(__VA_ARGS__)); return *this;} 
#define FLUENTIZE_PROCEDURE(name) CONCATENATE(Fluent,CURRENT_BASE)& f_ ## name() {name(); return *this;} 
#define FLUENTIZE_DFLT_CONSTRUCTOR(name) CONCATENATE(Fluent,CURRENT_BASE)() {} 
#define FLUENTIZE_CONSTRUCTOR(...) CONCATENATE(Fluent,CURRENT_BASE)(MODIFY_ARGS(__VA_ARGS__)) : CURRENT_BASE(SEQUENCE(__VA_ARGS__)) {} 

Hinweis: _x_ steht für Typ und _x steht für Argument-Namen.

Jetzt haben wir nicht fließend Klasse:

class Simple { 
    int i=0; 
public: 
    Simple() : Simple(0) {} 
    Simple(int i) {this->i = i;} 
    void setValue(int i) {this->i = i;} 
    void multiplyValue(int i) {this->i *= i;} 
    void halve() {this->i /= 2;} 
    int getValue() {return this->i;} 

}; 

Und das ist, wie fließend Klasse neu zu erstellen:

#define CURRENT_BASE Simple 
class FLUENTIZE_DERIVE() { 
public: 
    FLUENTIZE_DFLT_CONSTRUCTOR() 
    FLUENTIZE_CONSTRUCTOR(int) 
    FLUENTIZE_METHOD(setValue, int) 
    FLUENTIZE_METHOD(multiplyValue, int) 
    FLUENTIZE_PROCEDURE(halve) 
}; 
#undef CURRENT_BASE 

Damit haben wir Klasse FluentSimple genannt, mit fließend Methoden f_setValue, f_multiplyValue und f_halve. Mit etwas Makrozauber habe ich automatisch Funktionsargumente benannt (Argumente werden als Sequenz _1, _2, _3 ..., bis zu _5 zum Testen genannt). Beachten Sie, dass ich ein anderes Makro für Methoden erstellen musste, die keine Argumente übernehmen, da die Makro-Technik, die ich verwendete, nicht mit leerem Makro __VA_ARGS__ umgehen kann.

Nun das ist, wie die fließend Klasse zu verwenden:

std::cout << 
FluentSimple() 
    .f_setValue(10) 
    .f_multiplyValue(10) 
    .f_halve() 
    .getValue() << std::endl; 

Beachten Sie auch, dass bei dieser Konstruktion, fließend Klasse Zugriff auf alle Basisklasse Methoden hat und einige Funktionen wie Qt-Slots und Signale.

Wenn es irgendwelche Nachteile, außer Verwendung von Makros, lass es mich wissen :)

Verwandte Themen