泚é
ããã¯ãçæçãªãã¶ã€ã³ãã¿ãŒã³ãšé¢é£ããåé¡ã«ã€ããŠåçºããã3çªç®ã®èšäºã§ãã ããã§ã¯ããªããžã§ã¯ãããã¡ã¯ããªãŒã
ã¯ããã«
ããããå€ãã®äººãã çæçãªãã¶ã€ã³ãã¿ãŒã³ãèããããèªãã ãã䜿çšãããããŸãã[4] ã ãã®èšäºã§ã¯ããããã«ã€ããŠã®ã¿èª¬æããŸãã ãã ããããã§ã¯ä»ã®ããšã«éç¹ã眮ããŸãã ãã¡ããããã®èšäºã¯çæãã¿ãŒã³ã®ã¬ã€ããšããŠããŸãã¯ãããã®çŽ¹ä»ãšããŠäœ¿çšã§ããŸãã ããããç§ã®æçµçãªç®æšã¯ããããã«ç°ãªãé¢ãã€ãŸãããããã®ãã³ãã¬ãŒããå®éã®ã³ãŒãã§äœ¿çšããé¢ã§ãã
ãã³ãã¬ãŒãã«ã€ããŠåŠãã å€ãã®äººãã©ãã§ããã³ãã¬ãŒãã䜿ãå§ããããšããã®ã¯ç§å¯ã§ã¯ãããŸããã ãã ãããã¹ãŠãããã»ã©åçŽã§ã¯ãããŸããã ãã®ãããã¯ã«é¢ããå€ãã®èšäºã¯ãã³ãŒãã§ã®äœ¿çšã«ååãªæ³šæãæã£ãŠããŸããã ãããŠããã³ãã¬ãŒããã³ãŒãã«åºå®ãå§ãããšãããšã話ã§ããã³ã§ã説æã§ããªãã»ã©æ³åã絶ããäœããçããŸãã ç§ã¯ãããã®ã¢ã€ãã¢ã®ããŸããŸãªå身ãèŠãŠããŸããããæã èªçºçã«è³ªåãããŸããèè ã¯äœãåžã£ãŠããã®ã§ããïŒ ããšãã°ã Wikipedia [3]ã®ãã¡ã¯ããªãŒãŸãã¯ãã¡ã¯ããªãŒã»ã¡ãœãããåãäžããŸãã ãã¹ãŠã®ã³ãŒããæäŸããã®ã§ã¯ãªãã次ã®ãã®ã®ã¿ã䜿çšããŸãã
const size_t count = 2; // An array of creators Creator* creators[count] = { new ConcreteCreatorA(), new ConcreteCreatorB() }; // Iterate over creators and create products for (size_t i = 0; i < count; i++) { Product* product = creators[i]->factoryMethod(); cout << product->getName() << endl; delete product; } for (size_t i = 0; i < count; i++) delete creators[i];
å®éã®ç掻ã§ãããã©ã®ããã«äœ¿çšããããèªåãããšãããã«æ¬¡ã®çºèšãèµ·ãããŸãïŒ
- 0çªç®ãŸãã¯1çªç®ã®èŠçŽ ã䜿çšããå¿ èŠãããããšãã©ã®ããã«ããŠç¥ãããšãã§ããŸããïŒ éãã¯ãããŸããã
- ã«ãŒãå ã«ããã€ãã®èŠçŽ ãäœæããå¿ èŠããããšããŸãã ãããã®å·¥å Žã®æåšå°ã«é¢ããæ å ±ã¯ã©ãã§å ¥æã§ããŸããïŒ ããã«å·¥å Žãåæåããå Žåããªãããããå¿ èŠãªã®ã§ããïŒ ãªããžã§ã¯ããäœæãããã¹ãŠãå®è¡ããç¹å®ã®ã¡ãœãããŸãã¯ã¹ã¿ã³ãã¢ãã³é¢æ°ãåŒã³åºãããšãã§ããŸãã
- ãªããžã§ã¯ãã¯ãnewãªãã¬ãŒã¿ãŒã«ãã£ãŠäœæããããšæ³å®ãããŠããŸãã ããã«ãããäŸå€çãªç¶æ³ã®åŠçãšãªããžã§ã¯ãã®åç¶æéã®åé¡ãããã«çºçããŸãã
奜ããšå¥œãŸãããšã«ãããããããã®äŸã¯ãå€ãã®æ¬ é¥ãå«ãäžçš®ã®èª¬æã«ãããŸããã å®éã«ã¯ãããã¯äœ¿çšãããŸããã
ãããããäœã䜿ãããŸããïŒãã泚ææ·±ãèªè ã¯å°ããŸãã 以äžã«äœ¿çšã³ãŒãã瀺ããŸãã ãã®ãªã¹ãã¯å®å šãªãã®ã§ã¯ãããŸããã
// , , Object* o = Factory::getInstance().createObject("object_name"); // Configuration* conf = Configuration::getCurrentConfiguration(); Object* o = Factory::getInstance().createObject(conf->getObjectNameToCreate());
ãå®ç掻ãã®å·¥å Žã¯éåžžã·ã³ã°ã«ãã³ã§ããããšã¯æ³šç®ã«å€ããŸãã ãŸãããªããžã§ã¯ããäœæãããšãã«ã䜿çšãããã¿ãŒã³ããè³ãçªãåºãŠããããšã«ãæ°ä»ãããšãã§ããŸãã ãã®åŸã®ãªãã¡ã¯ã¿ãªã³ã°ã«ãããããã¯äžå¿«ãªåŽé¢ããæããããŸãã ãªããžã§ã¯ãããã€ã³ã¿ãŒã§è¿ãå Žåãã¢ãããŒãããã䜿çšãããŸãã ãã¹ãŠã®æ¬ã§æããããŠããããã«ãã³ãŒãã¯æžããç¶ããŠããŸãã createObjectã¡ãœããã§ãã¹ãŠãæ確ãªå Žå-æåŸã«deleteãåŒã³åºãå¿ èŠããããŸãããã®åŸãèšå®ãã©ãããŸããïŒ ã·ã³ã°ã«ãã³ãã©ããïŒ ãããããªããäœãããå¿ èŠã¯ãããŸããã ããã§ãªãå Žåã¯ïŒ ç¹°ãè¿ãã«ãªããŸãããç涯ã«ããã£ãŠçåãçããŸãã äŸå€ãæ£ããåŠçããããšãå¿ããªãã§ãã ãããäŸå€åŠçã䜿çšãããã®ãããªã³ãŒãã¯ããªãœãŒã¹ã®ã¯ãªãŒãã³ã°ã«é¢é£ããåé¡ãåŒãèµ·ãããŸãã
奜ããšå¥œãŸãããšã«ããããããçæããããªããžã§ã¯ããèµ€ãã¹ã¬ããã§åŠçããããŸããŸãªäœææ¹æ³ãåºå¥ããªãçµ±äžçãªã¢ãããŒããå¿ èŠã§ãã ãããå®è£ ããããã«ãäŸåé¢ä¿å転ã®åŒ·åãªååã䜿çšããŸã[7] ã ãã®æ¬è³ªã¯ãç¹å®ã®æœè±¡åãã€ã³ã¿ãŒãã§ãŒã¹ãå°å ¥ãããŠããããšã§ãã ããã«ã䜿çšã³ãŒããšäœ¿çšã³ãŒãã¯ãå°å ¥ãããã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠãããšãã°å¶åŸ¡å転[8]ã䜿çšããŠæ¥ç¶ãããŸãã ããã«ããããªããžã§ã¯ããäœæããã³ãŒãã¯ãã¯ã©ã¹äœæã®è©³çŽ°ããæœè±¡åããåçŽã«å°çšã€ã³ã¿ãŒãã§ã€ã¹ã䜿çšããããšãã§ããŸãã ãã¹ãŠã®æ³šæã¯ããã®ã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããæ©èœã®è©ã«ããã£ãŠããŸãã ãã®èšäºã§ã¯ãã»ãšãã©ãã¹ãŠã®æ¢ç¥ã®çæãã¶ã€ã³ãã¿ãŒã³ã䜿çšããŠãªããžã§ã¯ããäœæããæ¹æ³ãšãè€æ°ã®çæãã¿ãŒã³ã䜿çšããŠåæã«ã€ã³ã¹ã¿ã³ã¹ãäœæããäŸã«ã€ããŠè©³ãã説æããŸãã ã·ã³ã°ã«ãã³ã®äŸã¯ã 以åã®èšäº[2]ã§è©³çŽ°ã«èª¬æãããŠããŸã ããã®èšäºã§ã¯ãä»ã®ãã³ãã¬ãŒãã§ã®ã¿ããã䜿çšããŸãã
ã€ã³ãã©
Object Anãšãã®åšèŸºã®ã€ã³ãã©ã¹ãã©ã¯ãã£ã«ã€ããŠã¯ã 2çªç®ã®èšäº[2]ã§è©³ãã説æããŠããŸãã ããã§ã¯ãåŸç¶ã®ãã¬ãŒã·ã§ã³ã§äœ¿çšãããã³ãŒãã®ã¿ãæäŸããŸãã 詳现ã«ã€ããŠã¯ã 以åã®èšäº[2]ãåç §ããŠãã ããã
template<typename T> struct An { template<typename U> friend struct An; An() {} template<typename U> An(const An<U>& a) : data(a.data) {} template<typename U> An(An<U>&& a) : data(std::move(a.data)) {} T* operator->() { return get0(); } const T* operator->() const { return get0(); } bool isEmpty() const { return !data; } void clear() { data.reset(); } void init() { if (!data) reinit(); } void reinit() { anFill(*this); } T& create() { return create<T>(); } template<typename U> U& create() { U* u = new U; data.reset(u); return *u; } template<typename U> void produce(U&& u) { anProduce(*this, u); } template<typename U> void copy(const An<U>& a) { data.reset(new U(*a.data)); } private: T* get0() const { const_cast<An*>(this)->init(); return data.get(); } std::shared_ptr<T> data; }; template<typename T> void anFill(An<T>& a) { throw std::runtime_error(std::string("Cannot find implementation for interface: ") + typeid(T).name()); } template<typename T> struct AnAutoCreate : An<T> { AnAutoCreate() { create(); } }; template<typename T> T& single() { static T t; return t; } template<typename T> An<T> anSingle() { return single<AnAutoCreate<T>>(); } #define PROTO_IFACE(D_iface, D_an) \ template<> void anFill<D_iface>(An<D_iface>& D_an) #define DECLARE_IMPL(D_iface) \ PROTO_IFACE(D_iface, a); #define BIND_TO_IMPL(D_iface, D_impl) \ PROTO_IFACE(D_iface, a) { a.create<D_impl>(); } #define BIND_TO_SELF(D_impl) \ BIND_TO_IMPL(D_impl, D_impl) #define BIND_TO_IMPL_SINGLE(D_iface, D_impl) \ PROTO_IFACE(D_iface, a) { a = anSingle<D_impl>(); } #define BIND_TO_SELF_SINGLE(D_impl) \ BIND_TO_IMPL_SINGLE(D_impl, D_impl) #define BIND_TO_IFACE(D_iface, D_ifaceFrom) \ PROTO_IFACE(D_iface, a) { anFill<D_ifaceFrom>(a); } #define BIND_TO_PROTOTYPE(D_iface, D_prototype) \ PROTO_IFACE(D_iface, a) { a.copy(anSingle<D_prototype>()); }
ã€ãŸããAnãªããžã§ã¯ãã¯ãã¹ããŒãããã€ã³ã¿ãŒã§ãããanFillé¢æ°ã䜿çšããŠã¢ã¯ã»ã¹ãããšèªåçã«èšå®ãããŸãã å¿ èŠãªã€ã³ã¿ãŒãã§ã€ã¹ã«ãã®é¢æ°ããªãŒããŒããŒãããŸãã å ¥åããŒã¿ã«åºã¥ããŠãªããžã§ã¯ããäœæããã«ã¯ãanProduceé¢æ°ã䜿çšããŸãããã®äœ¿çšæ¹æ³ã«ã€ããŠã¯ããã¡ã¯ããªãŒã®ã»ã¯ã·ã§ã³ã§èª¬æããŸãã
ããªããžãã³ãã¬ãŒã
æãåçŽã§æãäžè¬çãªã±ãŒã¹ããå§ããŸãããããªããžã§ã¯ãããŒã¿ãé衚瀺ã«ãã䜿çšããã€ã³ã¿ãŒãã§ã€ã¹ã®ã¿ãæ®ããŸãã ãããã£ãŠãããšãã°ã1ã€ã®ãã£ãŒã«ããã¯ã©ã¹ã«è¿œå ãããªã©ãããŒã¿ãå€æŽããå Žåããã®ã¯ã©ã¹ã䜿çšãããã¹ãŠãåã³ã³ãã€ã«ããå¿ èŠã¯ãããŸããã ãã®èšèšãã¿ãŒã³ã¯ãããªããžããšåŒã°ãããã³ãã³ã®ã€ãã£ãªã ã«ã€ããŠã話ããŸãã ãã®ã¢ãããŒãã¯ãå€ãã®å Žåãã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ããåé¢ããããã«äœ¿çšãããŸãã
// header file // struct IObject { virtual ~IObject() {} }; struct IFruit : IObject { virtual std::string getName() = 0; }; // IFruit DECLARE_IMPL(IFruit) // cpp file struct Orange : IFruit { virtual std::string getName() { return "Orange"; } }; // IFruit Orange BIND_TO_IMPL(IFruit, Orange)
ãŸããåæœè±¡ã¯ã©ã¹ã«ä»®æ³ãã¹ãã©ã¯ã¿ãèšè¿°ããªãããã«ãIObjectã¯ã©ã¹ãäœæããŸãã 次ã«ãIObjectããåã€ã³ã¿ãŒãã§ã€ã¹ïŒæœè±¡ã¯ã©ââã¹ïŒãåçŽã«ç¶æ¿ããŸãã IFruitã€ã³ã¿ãŒãã§ãŒã¹ã«ã¯ãã¢ãããŒãã説æããåäžã®getNameïŒïŒé¢æ°ãå«ãŸããŠããŸãã 宣èšå šäœãããããŒãã¡ã€ã«ã§è¡ãããŸãã ç¹å®ã®å®è£ ã¯ããã§ã«cppãã¡ã€ã«ã«æžã蟌ãŸããŠããŸãã ããã§getNameïŒïŒé¢æ°ãå®çŸ©ããã€ã³ã¿ãŒãã§ã€ã¹ãå®è£ ã«ãã€ã³ãããŸãã Orangeã¯ã©ã¹ãžã®å€æŽãå€æŽãããšãã¯ã1ã€ã®ãã¡ã€ã«ãåã³ã³ãã€ã«ããã ãã§ãã
ã®äœ¿çšãèŠãŠã¿ãŸãããïŒ
An<IFruit> f; std::cout << "Name: " << f->getName() << std::endl; // output Name: Orange
ããã§ã¯ãåã«Anãªããžã§ã¯ããäœæããæåã®ã¢ã¯ã»ã¹æã«ãcppãã¡ã€ã«ã«èšè¿°ãããŠããç®çã®å®è£ ã§ãªããžã§ã¯ããäœæãããŸãã 寿åœã¯èªåçã«å¶åŸ¡ãããŸãã é¢æ°ãçµäºãããšããªããžã§ã¯ãã¯èªåçã«ç Žæ£ãããŸãã
å·¥å Žãã³ãã¬ãŒã
次ã«ãæãäžè¬çãªãã¿ãŒã³ã«ã€ããŠèª¬æããŸãããããã¡ã¯ããªã¡ãœãããŸãã¯ãã¡ã¯ããªã ãã§ãã ããã§ã¯ããã¡ã¯ããªãéåžžã©ã®ããã«äœ¿çšããããã®äŸã瀺ããŸããã ããã¯ãããšãã°Wikipediaã§èªãããšãã§ããŸãã ãã®ãã¶ã€ã³ãã¿ãŒã³ã®ãããã«ç°ãªã䜿çšæ¹æ³ã瀺ããŸãã
䜿çšæ³ã®éãã¯ãã»ãšãã©ã®å ŽåããŠãŒã¶ãŒã«ã¯èŠããªããšããããšã§ãã ããããããã¯å¶éããããšããæå³ã§ã¯ãããŸããã ãã®èšäºã§ã¯ãææ¡ãããã¢ãããŒãã®æè»æ§ãšåŒ·åºŠãå®èšŒããŸãã
ãã®ããã«ãåé¡ãæèµ·ããŸããé¢æ°ã®å ¥åãã©ã¡ãŒã¿ãŒã«å¿ããŠããŸããŸãªãªããžã§ã¯ããäœæããå¿ èŠããããŸãã äžè¬çã«èšãã°ãçæé¢æ°ã¯ããã€ãã®ãã©ã¡ãŒã¿ãŒãæã€ããšãã§ããŸãã ãã ããäžè¬æ§ã倱ãããšãªããããã€ãã®ãã©ã¡ãŒã¿ãŒãæã€é¢æ°ã¯ãå¿ èŠãªå ¥åããŒã¿ãæã€æ§é äœãåŒæ°ãšããŠäœ¿çšããã1ã€ã®ãã©ã¡ãŒã¿ãŒãæã€é¢æ°ã«éå ã§ãããšæ³å®ã§ããŸãã ãããã£ãŠãã€ã³ã¿ãŒãã§ã€ã¹ãšç解ãç°¡çŽ åããããã«ãã©ãã§ãã©ãã§ã1ã€ã®ãã©ã¡ãŒã¿ãŒãæã€é¢æ°ã䜿çšããŸãã èå³ã®ãã人ã¯ãæ°ããc ++ 0xæšæºã®å¯å€ãã³ãã¬ãŒãã䜿çšã§ããŸãããæ®å¿µãªããmsvcããã³iccã³ã³ãã€ã©ã¯ãŸã ãµããŒãããŠããŸããã
ãã®ããããã«ãŒãFruitTypeã®ã¿ã€ãã«å¿ããŠãIFruitã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ãäœæããã¿ã¹ã¯ã«çŽé¢ããŠããŸãã
enum FruitType { FT_ORANGE, FT_APPLE };
ãããè¡ãã«ã¯ãAppleã®è¿œå ã®å®è£ ãå¿ èŠã§ãã
// cpp file struct Apple : IFruit { virtual std::string getName() { return "Apple"; } };
çæé¢æ°ãäœæããŸãã
void anProduce(An<IFruit>& a, FruitType type) { switch (type) { case FT_ORANGE: a.create<Orange>(); break; case FT_APPLE: a.create<Apple>(); break; default: throw std::runtime_error("Unknown fruit type"); } }
ãã®é¢æ°ã¯ã以äžã«ç€ºãããã«ãAn :: produceã¡ãœãããåŒã³åºããããšèªåçã«åŒã³åºãããŸãã
An<IFruit> f; f.produce(FT_ORANGE); std::cout << f->getName() << std::endl; f.produce(FT_APPLE); std::cout << f->getName() << std::endl; // output: Orange Apple
å€ãã®å Žåãéã©ã³ã¿ã€ã å€ã«å¿ããŠãªããžã§ã¯ããäœæãããšäŸ¿å©ã§ãã ãã€ã§ããã©ã®ãªããžã§ã¯ããäœæãããããæ確ã«ããããŸãã ãã®åŸãä»ã®ããç°¡åãªæ¹æ³ã§äœæã§ããŸãã æåã®æ¹æ³ã¯ãäžéãªããžã§ã¯ããäœæããããšã§ã-ã¿ã°ïŒ
// struct OrangeTag {}; struct AppleTag {}; // cpp void anProduce(An<IFruit>& a, OrangeTag) { a.create<Orange>(); } void anProduce(An<IFruit>& a, AppleTag) { a.create<Apple>(); } // An<IFruit> f; f.produce(AppleTag()); std::cout << f->getName() << std::endl; f.produce(OrangeTag()); std::cout << f->getName() << std::endl; // output Apple Orange
2çªç®ã®ãªãã·ã§ã³ã¯ãç¹å¥ãªã€ã³ã¿ãŒãã§ã€ã¹ãäœæãããããªããžããã³ãã¬ãŒãã䜿çšããããšã§ãã
// header file struct IOrange : IFruit {}; DECLARE_IMPL(IOrange) struct IApple : IFruit {}; DECLARE_IMPL(IApple) // cpp file struct Orange : IOrange { virtual std::string getName() { return "Orange"; } }; BIND_TO_IMPL(IOrange, Orange); struct Apple : IApple { virtual std::string getName() { return "Apple"; } }; BIND_TO_IMPL(IApple, Apple); // An<IOrange> o; std::cout << "Name: " << o->getName() << std::endl; An<IApple> a; std::cout << "Name: " << a->getName() << std::endl; // output Name: Orange Name: Apple
ãã«ããŒãã³ãã¬ãŒã
å€ãã®äººïŒèªåãå«ãïŒã¯å°æããŠããŸãããå·¥å Žãããã®ã«ãªããã«ããŒãå¿ èŠãªã®ã§ããããïŒ å®éãå®éã«ã¯ããããã¯åæ§ã®ãã¿ãŒã³ã§ãã ãããã¯ã©ãéãã®ã§ããïŒ
ãããã次ã®åçŽãªæ¹æ³ã§æ確ã«åºå¥ããŸãããã¡ã¯ããªãŒã¯ã€ã³ã¹ã¿ã³ã¹ã®äœæã«äœ¿çšããããã®ã¿ã€ãã¯æž¡ããããã©ã¡ãŒã¿ãŒã«äŸåããŸãã ã¿ã€ããããã£ãŠãããšãã«ãã«ããŒã䜿çšãããŸããããªããžã§ã¯ãã®ãã£ãŒã«ãã«å ¥åããæ¹æ³ã¯ããŸããŸã§ãã ã€ãŸã ãã¡ã¯ããªãŒã¯ç°ãªãã¿ã€ããäœæããŸãããã«ããŒã®å Žåãåãã¿ã€ãã䜿çšãããŸãããå 容ã¯ç°ãªããŸãã ããã§ã¯ãäŸããå§ããŸãããã
// header file struct Fruit { Fruit(const std::string& name) : m_name(name) {} std::string getName() { return m_name; } private: std::string m_name; }; // cpp file struct Orange : Fruit { Orange() : Fruit("Orange") {} }; struct Apple : Fruit { Apple() : Fruit("Apple") {} }; enum FruitType { FT_ORANGE, FT_APPLE }; void anProduce(An<Fruit>& a, FruitType type) { switch (type) { case FT_ORANGE: a.create<Orange>(); break; case FT_APPLE: a.create<Apple>(); break; default: throw std::runtime_error("Unknown fruit type"); } }
ããã«ã¯ãFruitã¯ã©ã¹ããããŸãããããã¯ãã¯ãæœè±¡ã§ã¯ãããŸããã 䜿ãæ £ããgetNameïŒïŒã¡ãœãããå«ãŸããŠããŸãããã®ã¡ãœããã¯ãåã«ã¯ã©ã¹ã®ã³ã³ãã³ãããç®çã®ã¿ã€ããæœåºããŸãã ãã«ããŒã®ã¿ã¹ã¯ã¯ããã®ãã£ãŒã«ãã«æ£ããå ¥åããããšã§ãã ãã®ããã«ã2ã€ã®ã¯ã©ã¹ã䜿çšããããã¶ã€ããŒã¯ãã®ãã£ãŒã«ãã«æ£ããå€ãå ¥åããŸãã çæé¢æ°anProduceã¯å¿ èŠãªã€ã³ã¹ã¿ã³ã¹ãäœæãããã®ã³ã³ã¹ãã©ã¯ã¿ãŒã¯å¿ èŠãªãã¹ãŠã®äœæ¥ãè¡ããŸãã
An<Fruit> f; f.produce(FT_ORANGE); std::cout << f->getName() << std::endl; f.produce(FT_APPLE); std::cout << f->getName() << std::endl; // output Orange Apple
æœè±¡ãã¡ã¯ããªãŒãã³ãã¬ãŒã
ãã®ãã³ãã¬ãŒãã¯ãç¹å®ã®é¢ä¿ãæã€ãªããžã§ã¯ãã®ã»ãããäœæããå¿ èŠãããå Žåã«äœ¿çšãããŸãã ãã®ã¢ãããŒãã説æããããã«ã次ã®äŸãæ€èšããŠãã ããã
GUIãªããžã§ã¯ããäœæããå¿ èŠããããšããŸãïŒ
struct IWindow : IObject { virtual std::string getWindowName() = 0; }; struct IButton : IObject { virtual std::string getButtonName() = 0; };
åæã«ããã®ãããªãªããžã§ã¯ããæäœã§ãããã¬ãŒã ã¯ãŒã¯ãããã€ããããŸãããã®ãã¡ã®1ã€ã¯ãããšãã°gtkã§ãã ãããè¡ãã«ã¯ããªããžã§ã¯ããçæããããã®ã€ã³ã¿ãŒãã§ã€ã¹ãäœæããŸãã
struct IWindowsManager : IObject { virtual void produceWindow(An<IWindow>& a) = 0; virtual void produceButton(An<IButton>& a) = 0; };
次ã«ãå®è£ ã宣èšããŸãã
struct GtkWindow : IWindow { virtual std::string getWindowName() { return "GtkWindow"; } }; struct GtkButton : IButton { virtual std::string getButtonName() { return "GtkButton"; } }; struct GtkWindowsManager : IWindowsManager { virtual void produceWindow(An<IWindow>& a) { a.create<GtkWindow>(); } virtual void produceButton(An<IButton>& a) { a.create<GtkButton>(); } }; BIND_TO_IMPL_SINGLE(IWindowsManager, GtkWindowsManager)
ãããŠãçæé¢æ°ãäœæããŸãã
PROTO_IFACE(IWindow, a) { An<IWindowsManager> pwm; pwm->produceWindow(a); } PROTO_IFACE(IButton, a) { An<IWindowsManager> pwm; pwm->produceButton(a); }
ããã§ãã€ã³ã¿ãŒãã§ã€ã¹ã䜿çšã§ããŸãã
An<IButton> b; std::cout << b->getWindowName() << std::endl; An<IWindow> w; std::cout << w->getButtonName() << std::endl; // output GtkButton GtkWindow
äŸãè€éã«ããŸãããã æ§æã«å¿ããŠãã¬ãŒã ã¯ãŒã¯ãéžæããå¿ èŠããããšããŸãããã ãããã©ã®ããã«å®è£ ã§ããããèŠãŠãããŸãã
enum ManagerType { MT_GTK, MT_UNKNOWN }; // struct Configuration { // Configuration() : wmType(MT_UNKNOWN) {} ManagerType wmType; }; // () BIND_TO_SELF_SINGLE(Configuration) // struct WindowsManager { // , [1] An<IWindowsManager> aWindowsManager; An<Configuration> aConfiguration; WindowsManager() { switch (aConfiguration->wmType) { case MT_GTK: aWindowsManager.create<GtkWindowsManager>(); break; default: throw std::runtime_error("Unknown manager type"); } } }; BIND_TO_SELF_SINGLE(WindowsManager) // IWindow PROTO_IFACE(IWindow, a) { An<WindowsManager> wm; wm->aWindowsManager->produceWindow(a); } // IButton PROTO_IFACE(IButton, a) { An<WindowsManager> wm; wm->aWindowsManager->produceButton(a); } // An<Configuration> conf; conf->wmType = MT_GTK; // gtk An<IButton> b; std::cout << b->getButtonName() << std::endl; An<IWindow> w; std::cout << w->getWindowName() << std::endl; // output GtkButton GtkWindow
ãããã¿ã€ããã³ãã¬ãŒã
ãã®ãã³ãã¬ãŒãã䜿çšãããšãæ¢åã®ãªããžã§ã¯ããè€è£œããããšã«ãããè€éãªãŸãã¯ãéãããªããžã§ã¯ããäœæã§ããŸãã å€ãã®å Žåããã®ãã³ãã¬ãŒãã¯ãè€è£œããããªããžã§ã¯ããä¿åããã·ã³ã°ã«ãã³ãã³ãã¬ãŒããšçµã¿åãããŠäœ¿çšââãããŸãã äŸãèããŠã¿ãŸãããïŒ
// header file struct ComplexObject { std::string name; }; // ComplexObject DECLARE_IMPL(ComplexObject) // cpp file struct ProtoComplexObject : ComplexObject { ProtoComplexObject() { name = "ComplexObject from prototype"; } }; // ComplexObject ProtoComplexObject BIND_TO_PROTOTYPE(ComplexObject, ProtoComplexObject)
ããã«ã¯ãäœæããå¿ èŠã®ããè€éã§éãã¯ã©ã¹ã®ComplexObjectããããŸãã ãã®ã¯ã©ã¹ãäœæããã«ã¯ãã·ã³ã°ã«ãã³ããååŸããProtoComplexObjectãªããžã§ã¯ããã³ããŒããŸãã
#define BIND_TO_PROTOTYPE(D_iface, D_prototype) \ PROTO_IFACE(D_iface, a) { a.copy(anSingle<D_prototype>()); }
ããã§ããããã¿ã€ãã次ã®ããã«äœ¿çšã§ããŸãã
An<ComplexObject> o; std::cout << o->name << std::endl; // output ComplexObject from prototype
ãã«ããã³ãã³ãã¬ãŒã
ããšãã°ãå¿ èŠãªæ å ±ãååŸããããã«ãããŒã¿ã»ã³ã¿ãŒãžã®æ¥ç¶ãäœæããå¿ èŠããããšããŸãã ããŒã¿ã»ã³ã¿ãŒãéè² è·ã«ããªãããã«ãåããŒã¿ã»ã³ã¿ãŒãžã®æ¥ç¶ã1ã€ã ã䜿çšããå¿ èŠããããŸãã ããŒã¿ã»ã³ã¿ãŒã1ã€ãããªãå Žåã¯ãã·ã³ã°ã«ãã³ã䜿çšããæ¯åããã䜿çšããŠã¡ãã»ãŒãž/ãªã¯ãšã¹ããéä¿¡ããŸãã ãã ãã2ã€ã®åäžã®ããŒã¿ã»ã³ã¿ãŒãããããããã®éã§è² è·ã®ãã©ã³ã¹ãåãå¿ èŠããããŸãã å¯èœã§ããã°ãäž¡æ¹ã®ããŒã¿ã»ã³ã¿ãŒã䜿çšããŠãã ããã ãããã£ãŠãã·ã³ã°ã«ãã³ã¯ããã§ã¯é©ããŠããŸãããããã«ããã³ã¯é©ããŠããŸããããã«ããããªããžã§ã¯ãã®è€æ°ã®ã€ã³ã¹ã¿ã³ã¹ããµããŒãã§ããŸãã
// header // struct IConnection : IObject { virtual void send(const Buffer& buf) = 0; virtual Buffer recieve(size_t bytes) = 0; }; // DECLARE_IMPL(IConnection) // cpp file // struct DataCenterConnection : IConnection { DataCenterConnection() { std::cout << "Creating new connection" << std::endl; // ... } ~DataCenterConnection() { std::cout << "Destroying connection" << std::endl; // ... } // recieve & send // ... }; // , struct ConnectionManager { ConnectionManager() : connectionCount(0), connections(connectionLimit) { } void fillConnection(An<IConnection>& connection) { std::cout << "Filling connection: " << connectionCount + 1 << std::endl; if (connectionCount < connectionLimit) { // connections[connectionCount].create<DataCenterConnection>(); } // connection = connections[connectionCount ++ % connectionLimit]; } private: // static const size_t connectionLimit = 2; // size_t connectionCount; std::vector<An<IConnection>> connections; }; // BIND_TO_SELF_SINGLE(ConnectionManager) // IConnection PROTO_IFACE(IConnection, connection) { An<ConnectionManager> manager; manager->fillConnection(connection); } // for (int i = 0; i < 5; ++ i) { An<IConnection> connection; connection->send(...); } // output Filling connection: 1 Creating new connection Filling connection: 2 Creating new connection Filling connection: 3 Filling connection: 4 Filling connection: 5 Destroying connection Destroying connection
å®è£ ã«ã¯ãæãåçŽãªæ¥ç¶ãã©ã³ã·ã³ã°ã¢ã«ãŽãªãºã ã䜿çšãããŸãããæ¥ç¶ã䜿çšããããã®æ°ããèŠæ±ã¯ããããã次ã®ããŒã¿ã»ã³ã¿ãŒã«ãªãã€ã¬ã¯ããããŸãã ããã¯ããã®èšèšãã¿ãŒã³ã®å¹æã説æããã®ã«ååã§ããæåã«2ã€ã®æ¥ç¶ãäœæãããæ°ããæ¥ç¶ãªããžã§ã¯ãã«åå©çšãããŸãã ããã°ã©ã ã®æåŸã«ããããã¯èªåçã«ç Žæ£ãããŸãã
ã·ã³ã°ã«ãã³ããã¡ã¯ããªãŒãããã³ãããã¿ã€ã
æåŸã®äŸã§ã¯ãããã€ãã®çæãã¿ãŒã³ã®çžä¹å¹æãæ€èšããŸãã æž¡ãããå€ã«å¿ããŠç°ãªããªããžã§ã¯ããäœæããå¿ èŠããããšããŸãã äœæãããããŸããŸãªã¿ã€ãã®æ°ã¯éåžžã«å€ããšæ³å®ãããŠãããããç®çã®ã¿ã€ããéžæããããã«ããªãè¿ éãªæ¹æ³ã䜿çšããããšæããŸãã ããã·ã¥é¢æ°ã䜿çšããæ€çŽ¢ã䜿çšããŸãã ç®çã®ã¿ã€ãã®åã€ã³ã¹ã¿ã³ã¹ã¯éåžžã«éããããã€ã³ã¹ã¿ã³ã¹ã®äœæã容æã«ããããã«ããããã¿ã€ãããã³ãã¬ãŒãã䜿çšããå¿ èŠããããŸãã åãããã¿ã€ããé 延çã«çæããããã€ãŸã å¿ èŠã«ãªããŸã§ãããã¿ã€ããäœæããªãã§ãã ããã ãŸãã圌ãããã®æ©èœã決ããŠäœ¿çšããªãå¯èœæ§ããããŸãããããã£ãŠããªããžã§ã¯ããçæããããã«äºåã«ãªããžã§ã¯ããäœæããå¿ èŠã¯ãããŸããã ãé 延ããã¡ã¯ããªãŒãäœæããŸãã
ããã§ã¯å§ããŸãããã æåã«ãäœæããã€ã³ã¿ãŒãã§ã€ã¹ãšãªããžã§ã¯ããäœæããŸãã
struct IShape : IObject { virtual std::string getShapeName() = 0; virtual int getLeftBoundary() = 0; }; struct Square : IShape { Square() { std::cout << "Square ctor" << std::endl; } Square(const Square& s) { std::cout << "Square copy ctor" << std::endl; } virtual std::string getShapeName() { return "Square"; } virtual int getLeftBoundary() { return m_x; } private: // upper left vertex int m_x; int m_y; // size of square int m_size; }; struct Circle : IShape { Circle() { std::cout << "Circle ctor" << std::endl; } Circle(const Circle& s) { std::cout << "Circle copy ctor" << std::endl; } virtual std::string getShapeName() { return "Circle"; } virtual int getLeftBoundary() { return m_x - m_radius; } private: // center of the circle int m_x; int m_y; // its radius int m_radius; };
ãã¹ãŠããæé·ãããããã«èŠããããã«ããå¿ èŠã®ãªãæ©èœãã¯ã©ã¹ã«è¿œå ããŸããã ã¯ã€ãã¯æ€çŽ¢ã®ããã«ãunordered_mapã䜿çšããŸããããã¯ãã³ã³ãã€ã©ãæ°ããæšæºããµããŒãããŠããå ŽåãboostãŸãã¯stdã®ããããã«ãããŸãã ããŒã¯åã瀺ãæååã§ãå€ã¯ç¹å®ã®åã®å¿ èŠãªã€ã³ã¹ã¿ã³ã¹ãçæãããªããžã§ã¯ãã«ãªããŸãã ãããè¡ãã«ã¯ãé©åãªã€ã³ã¿ãŒãã§ã€ã¹ãäœæããŸãã
// template<typename T> struct ICreator : IObject { virtual void create(An<T>& a) = 0; }; // , T_impl T template<typename T, typename T_impl> struct AnCreator : ICreator<T> { virtual void create(An<T>& a) { a.create<T_impl>(); } }; // , T_impl T, // , template<typename T, typename T_impl> struct AnCloner : ICreator<T> { virtual void create(An<T>& a) { a.copy(anSingle<T_impl>()); } };
ãªããªã éãæœèšãäœãäºå®ã§ãå·¥å Žã§ã¯AnClonerã䜿çšããŸãã
struct ShapeFactory { ShapeFactory() { std::cout << "ShareFactory ctor" << std::endl; // ICreator add<Square>("Square"); add<Circle>("Circle"); } template<typename T> void add(const std::string& type) { // AnCloner // AnAutoCreate An<ICreator<...>> m_creator.insert(std::make_pair(type, AnAutoCreate<AnCloner<IShape, T>>())); } void produce(An<IShape>& a, const std::string& type) { auto it = m_creator.find(type); if (it == m_creator.end()) throw std::runtime_error("Cannot clone the object for unknown type"); it->second->create(a); } private: std::unordered_map<std::string, An<ICreator<IShape>>> m_creator; }; // "" BIND_TO_SELF_SINGLE(ShapeFactory)
ããã§ãå·¥å Žã®æºåãæŽããŸãããã§ã¯ãæ¯ãåžã蟌ãã§ããªããžã§ã¯ããçæããæåŸã®é¢æ°ãè¿œå ããŸãããã
void anProduce(An<IShape>& a, const std::string& type) { An<ShapeFactory> factory; factory->produce(a, type); }
ããã§ããã¡ã¯ããªã䜿çšã§ããŸãã
std::cout << "Begin" << std::endl; An<IShape> shape; shape.produce("Square"); std::cout << "Name: " << shape->getShapeName() << std::endl; shape.produce("Circle"); std::cout << "Name: " << shape->getShapeName() << std::endl; shape.produce("Square"); std::cout << "Name: " << shape->getShapeName() << std::endl; shape.produce("Parallelogram"); std::cout << "Name: " << shape->getShapeName() << std::endl;
ç»é¢ã«åºåããããã®ïŒ
Begin ShareFactory ctor Square ctor Square copy ctor Name: Square Circle ctor Circle copy ctor Name: Circle Square copy ctor Name: Square Cannot clone the object for unknown type
ç§ãã¡ã«äœãèµ·ãã£ãŠããã®ããããã«è©³ããèããŠã¿ãŸãããã Beginã¯æåã«è¡šç€ºãããŸããããã¯ãäœãèµ·ãã£ãŠããã®ããšãããæ inessããèªããã¡ã¯ããªãŒããããã¿ã€ããªã©ããªããžã§ã¯ãããŸã äœæãããŠããªãããšãæå³ããŸãã次ã«ãshape.produceïŒ "Square"ïŒã®åŒã³åºãã«ãããäžé£ã®ã¢ã¯ã·ã§ã³å šäœãçæãããŸãããã¡ã¯ããªãŒïŒShareFactory ctorïŒãäœæããããããã¿ã€ãSquareïŒSquare ctorïŒãçæããããããã¿ã€ããã³ããŒããïŒSquare copy ctorïŒãç®çã®ãªããžã§ã¯ããè¿ãããŸãã getShapeNameïŒïŒã¡ãœãããåŒã³åºããæååSquareïŒååïŒSquareïŒãè¿ããŸãã Circleãªããžã§ã¯ãã§ãåæ§ã®ããã»ã¹ãçºçããŸãããçŸåšã¯ãã¡ã¯ããªããã§ã«äœæãããŠãããåäœæãšåæåã¯äžèŠã§ãã次ã«shape.produceïŒãSquareãïŒã䜿çšããŠSquareãäœæãããšãããããã¿ã€ãã®ã³ããŒã®ã¿ãåŒã³åºãããããã«ãªããŸããããããã¿ã€ãèªäœã¯ãã§ã«äœæãããŠããŸãïŒSquareã³ããŒã¯ã¿ãŒïŒãäžæãªå³åœ¢shape.produceïŒ "Parallelogram"ïŒãäœæããããšãããšãç°¡æœãã®ããã«çç¥ããããã³ãã©ãŒã§ãã£ãããããäŸå€ãã¹ããŒãããŸãïŒäžæãªã¿ã€ãã®ãªããžã§ã¯ããè€è£œã§ããŸããïŒã
çµè«
ãã®èšäºã§ã¯ãçæçãªãã¶ã€ã³ãã¿ãŒã³ãšãããŸããŸãªç¶æ³ã§ã®ãããã®äœ¿çšã«ã€ããŠèª¬æããŸãããã®èšäºã¯ããã®ãããªãã¿ãŒã³ã§å®å šã§ãããšäž»åŒµããŠããŸãããããã§ã¯ãèšèšãšå®è£ ã®æ®µéã§çºçããæ¢ç¥ã®åé¡ãšã¿ã¹ã¯ã«ã€ããŠãå°ãç°ãªãèŠè§£ã瀺ããããšæããŸããããã®ã¢ãããŒãã§ã¯ããã®èšäºã§èª¬æãããŠãããã¹ãŠã®åºç€ãšãªãéåžžã«éèŠãªååãäŸåé¢ä¿åŠçã®åå[7]ã䜿çšããŸããããããããç解ããããã«ã1ã€ã®ããŒãã«ã«ããŸããŸãªãã³ãã¬ãŒãã䜿çšããŠããŸãã
æ¯èŒè¡šïŒç¡æ¡ä»¶ã®ã€ã³ã¹ã¿ã³ã¹äœæ
æš¡æ§ | éåžžã®äœ¿çš | èšäºã§äœ¿çš |
---|---|---|
ã·ã³ã°ã«ãã³ |
|
|
æ© |
|
|
å·¥å Ž |
|
|
ãã«ããã³ |
|
|
æ¯èŒè¡šïŒå ¥åã«åºã¥ããã€ã³ã¹ã¿ã³ã¹ã®äœæ
æš¡æ§ | éåžžã®äœ¿çš | èšäºã§äœ¿çš |
---|---|---|
å·¥å Ž |
|
|
æœè±¡å·¥å Ž |
|
|
è©Šäœæ© |
|
|
ã·ã³ã°ã«ãã³ããããã¿ã€ãããã³å·¥å Ž |
|
|
å©ç¹ã¯æããã§ããå®è£ ã¯ã€ã³ã¿ãŒãã§ãŒã¹ã貫éããŸããããã®ã¢ãããŒãã«ãããã³ãŒããç¹å®ã®ã€ã³ã¹ã¿ã³ã¹äœæã¡ãœããããæœè±¡åãã解決ããåé¡ã«éäžããããšãã§ããŸããããã«ãããéåžžã«æè»ãªã¢ããªã±ãŒã·ã§ã³ãäœæã§ããé©åãªã³ãŒãããªãã¡ã¯ã¿ãªã³ã°ããå¿ èŠãªãå®è£ ãç°¡åã«å€æŽã§ããŸãã
次ã¯ïŒ
ãããŠãåç §ã®ãªã¹ããããŠã次ã®èšäºã§ã¯ããã«ãã¹ã¬ããã®åé¡ããã®ä»ã®èå³æ·±ãçããããã³ãã«ã€ããŠæ€èšããŸãã
æåŠ
[1] HabrahabrïŒã·ã³ã°ã«ãã³ãã¿ãŒã³ã®äœ¿çš
[2] HabrahabrïŒã·ã³ã°ã«ãã³ãšãªããžã§ã¯ãã®å¯¿åœ
[3] ãŠã£ãããã£ã¢ïŒãã¡ã¯ããªã¡ãœãã
[4] ãŠã£ãããã£ã¢ïŒãã¶ã€ã³ãã¿ãŒã³ã®çæ
[5] Andrey on .NETïŒãã¿ãŒã³ã®çæ
[6] Andrey on .NET ïŒãã¡ã¯ããªã¡ãœãã
[7] ãŠã£ãããã£ã¢ïŒäŸåé¢ä¿ã®å転ã®åç
[8] ãŠã£ãããã£ã¢ïŒå¶åŸ¡ã®å転