Object Factories (Object factory), objectfactories

Source: Internet
Author: User

Object Factories (Object factory), objectfactories
1. Why do we need an object factory?

When creating an object, we must provide the specific type, either new A or new B. Both A and B are object types. We have always opposed writing hardcode, but we must hardcode when creating an object.

What should I do if I want to create an object based on user input, network feedback, or text file information?

At first, we thought like this: pseudocode.

switch(Info){  case a: return new A;  case b: return new B;  ...  default:...}

This means that everyone is familiar with the simple factory model. Although simple, it contains a basic principle:Search for type (a, B...) based on value (A, B...) and create value (A *, B *...) using type *...).

Using the object factory, we get free when creating objects, without writing hardcode or providing types. We can provide numbers, strings, and specific format information to create an object.

Okay. This is the meaning of the existence of the object factory!

2. is a simple factory not perfect?

Yes, not perfect. There are three reasons:

  • It uses the switch statement, so it has the corresponding disadvantages of the switch statement. This is what object-oriented efforts are made to eliminate (switch itself is a kind of hardcode, so object-oriented: Polymorphism)
  • Factory classes need to collect all types of information produced by them. Compilation dependency is strong.
  • To add a new type, you need to modify the factory code. Generally, there are more than one type. (Introduce header files, add constants, and modify switches)
3. What are our goals?
  • The factory does not use the switch statement
  • The factory is scalable and can dynamically add or delete products.
  • The factory can be provided with raw materials for constructing objects, and the quantity is variable.
  • Generalized factory, which supports different types of abstract products without coding
  • Reduce memory management complexity
  • Type security as far as possible
4. Let's take a look at implementation. This is the key: (in the process of constantly improving the implementation, I found myself working in a pattern, so the following code is for reference only)
 1 struct package 2 { 3     void * funcSet; 4     void * func; 5     size_t index; 6     string sig; 7 }; 8   9 template <typename ...> class TypeList {};10  11 template <typename AbstractProduct ,typename IdentifierType = string> class FactoryImpl12 {13 public:14     template <typename... Arg> bool Register(const IdentifierType& id,const function<unique_ptr<AbstractProduct>(Arg...)>& creator)15     {16  17         static vector<function<unique_ptr<AbstractProduct>(Arg...)>> vf;18         typename AssocMap::const_iterator i =associations_.find(id);19         if(i!= associations_.end()) return false;20         vf.push_back(creator);21         return associations_.insert(typename AssocMap::value_type(id,package {&vf,&vf.back(),vf.size()-1,string(typeid(TypeList<Arg...>).name())})).second;22  23     }24  25     template <typename ... Arg >26     bool UnRegister(const IdentifierType& id)27     {28         typename AssocMap::const_iterator i =associations_.find(id);29         if(i != associations_.end())30         {31             assert(32                 ((i->second).sig).compare(typeid(TypeList<Arg...>).name())==033             );34             auto vf=static_cast<vector<function<unique_ptr<AbstractProduct>(Arg...)>>*>((i->second).funcSet);35             vf->erase(vf->begin()+(i->second).index);36         }37  38         return associations_.erase(id)==1;39     }40  41     template <typename... Arg> unique_ptr<AbstractProduct> Createobject(const IdentifierType& id,Arg&&... args)42     {43         typename AssocMap::const_iterator i =associations_.find(id);44  45         if(i != associations_.end())46         {47             assert(((i->second).sig).compare(typeid(TypeList<Arg...>).name())==0);48             auto funp=static_cast<function<unique_ptr<AbstractProduct>(Arg...)>* >((i->second).func);49             return (*funp)(std::forward<Arg>(args)...);50         }51         assert(false);52     }53  54  55 private:56     typedef std::unordered_map<IdentifierType,package> AssocMap;57     AssocMap associations_;58  59 };

 

Code:

  • What are 17 rows doing? Yes. The function object passed by the customer may have been released during the call. If we do not save a function object, we only convert its function object pointer to void *, afterwards, we are converting void * to the function object pointer. If the function object has been released during the call, a memory error will inevitably occur.
  • Because of Row 17, everything becomes very tricky. The most difficult to implement is the UnRegister function, which is also the biggest failure of this Code. UnRegister forces the customer to explicitly provide the correct type, otherwise it cannot work. Why must I provide a type? After the type is erased, the compiler cannot know the actual type. You must perform a forced conversion to delete the function object in the vector. Otherwise, the memory leaks until the process exits.
  • All functions are added with assert to prevent errors. If incorrect parameters are provided, the process is terminated.
  • In the code, std: function and unique_ptr are used. std: function is packaged into the same type for different forms of callable bodies, and unified calls are maintained. Unique_ptr is used to facilitate memory management.
  • In the 1-7package struct, func points to the function object provided by the user, funcSet points to static vector in the Register function, and index indicates its position in func pointer in funcSet. sig can be understood as the function signature.

Since variable parameters are not used in the class template, it is very difficult to implement them. I think the class template can be implemented with variable parameters. Although the classes instantiated by such a class template only support registration and fixed call bodies of call parameters, it has the advantage of checking the type during the compilation period and is easily implemented by Register and UnRegister. You can instantiate the template as needed.

template <typename AbstractProduct ,typename IdentifierType ,typename... Arg  > class Factory{public:    bool Register(const IdentifierType& id, std::function<unique_ptr<AbstractProduct> (Arg...)> creator)    {        return associations_.insert(typename AssocMap::value_type(id,creator)).second;    }    bool UnRegister(const IdentifierType& id)    {        return associations_.erase(id)==1;    }    unique_ptr<AbstractProduct> Createobject(const IdentifierType& id,Arg&&... args)    {        typename AssocMap::const_iterator i =associations_.find(id);        if(i != associations_.end())        {            return (i->second)(std::forward<Arg>(args)...);        }        assert(false);    }private:    typedef std::unordered_map<IdentifierType,std::function<unique_ptr<AbstractProduct> (Arg...)> > AssocMap;    AssocMap associations_;};

Note that the default template parameters cannot be used because the variable-length template parameters are used.

 

With the first implementation method, you only need one object to deal with all the requirements (UnRegister is quite disturbing ). Has a runtime type check.

In the second implementation method, you need to define the class in different scenarios, and create an object that only supports registering a call format call body. It also has a compilation period type check.

 

Although I have made a lot of effort in the first method, I still don't recommend this method unless it is really necessary, so I have to design the code like this.

Before the Spring Festival, indicate the source of the last article. Thank you.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.