Discuss the relationship between Factory model (Abstract Factory) and DIP
Most people refer to the Factory mode as the Abstract Factory mode in the GOF design mode.
This is a common and useful mode. What is the relationship between it and DIP principles?
DIP principles
DIP: Dependency inversion principle.
DIP refers to the principle of dependency inversion. It refers to that upper-layer modules should depend on interfaces, and specific classes should depend on abstract interfaces (that is, forced to implement abstract interfaces ). Abstract interfaces are closer to their users (upper-layer modules), so they look like a specific class depends on upper-layer modules. This is called Dependency inversion.
If we strictly follow DIP, any new statement violates DIP. For example:
class Pic{public: virtual void draw() = 0;};class Png : public Pic{public: virtual void draw() { printf("draw png\n"); }}void main(){ Png* p = new Png(); p->draw();}
Looking at the above Code, the main () function is used as the user of the Pic class library. new Png () itself violates DIP. Is this funny? This kind of code is very common. But it actually violates DIP. We can see the Png class in the Customer Code. The Png class is a specific class, which indicates that the customer depends on the specific class. Isn't that a violation of DIP? Strictly speaking, it is indeed a violation. However, it may not be too bad.How likely is the change of a Png class?If the Png class is basically not changed, the violation will be violated. It does not matter. Just as we use the classes in stl, those classes will almost never change, and the customer code will depend on them directly. Why. However, if the Png class is very likely to change, it is not very good to depend on the specific class at this time.
The above code, if changed:
void main(){ Pic* p = new Png(); p->draw();}
In this case, it will be much better, because only new depends on the specific class, And the pointer returned by new is saved in Pic * p. Pic * will be used in all other places, except for new itself, the rest depends on interfaces. But new itself is still illegal DIP. We can draw a picture:
In the figure above, as a customer, main () is strongly dependent (or associated) on the Pic interface, and then has a Png dependency (dotted line ). Indeed, there are many places in main () that need to call Pic * p, so it is associated. In new Pic (), it is a weak dependency. In fact, the above design is feasible in most cases, and there is no problem, it is also very common.
If the possibility of Png changes is very high, for example, the Png constructor changes frequently, or the possibility of creating other Pic subclasses is very high, or even the class name of Png changes. At this time, the figure above is a bit problematic. After all, main is weak dependent on specific classes.
At this time, we can consider the factory model. (GOF is called Abstract Factory ).
Abstract Factory)
We can consider evolving the above graph:
We disconnected the dependencies between main () and Png, and instead introduced a factory class PicFactory. Main () is associated with PicFactory, while PicFactory is dependent on Png. The code is roughly as follows:
class PicFactory{public: Pic* makePng() { return new Png() }};void main(){ PicFactory f; Pic* p = f.makePng();}
This is a simple factory. What are the benefits of doing so? Because the Png class is quite variable, we put it into the factory class. The customer main () only needs to use the factory class to create the Pic object. Someone will ask,We just depended on the Png class and now on the PicFactory class. What are the differences between them?The key lies in: the Png class or other Pic sub-classes are easy to change, while the factory class is relatively stable and dependent on a relatively stable class is always better than the class that is easy to change.
For example, we need to add a new Pic subclass called Gif. What we need to do is:
class Gif : public Pic{public: virtual void draw() { printf("Gif::draw\n"); }};class PicFactory{public: Pic* makePng() { return new Png(); } Pic* makeGif() { return new Gif(); }}void main(){ PicFactory f; Pic* gif = f.makeGif() gif->draw();}
1. added a Gif class.
2. Add a function makeGif () in PicFactory ()
3. The customer main can create Gif objects through the factory.
The problem with doing so is that every time a new Pic subclass is added, the factory needs to add a function, which is not very comfortable.
You can change the factory class:
typedef enum PicType{Png = 0, Gif};class PicFactory{public: Pic* makePic(PicType t) { Pic* p = nullptr; switch(t) { case Png: p = new Png(); break; case Gif: p = new Gif(); break; } return p; }}
In this way, every time we add a new Pic subclass, we don't need to add a new factory function. We just need to modify the makePic function. It is better than the original one.
Another benefit of the factory model is:The factory itself can also be replaced.
Factory mode (replaceable)
To solve this problem, Png has another implementation. This Png can be drawn in the Edit Control, for example, in the qq Edit box, which is called PngEx. There are two ways to modify the factory class at this time:
1. Add a new case in makePic and return the PngEx object.
2. Create a new factory class.
The specific usage depends on the specific situation. If we need to change the creation of a group of objects. So it may be better for #2.Generally, one of our factories creates a group of related products. To create another group of products, create another factory.For example, a factory creates a group of Pic objects that only support GDI painting, and a factory that supports direct x painting.
To achieve this effect,First, we need to transform the factory class. We need to create an Abstract interface for the factory class. In fact, this is the Abstract Server mode.
See:
OK. Now main () is dependent on the factory abstract class, which is more flexible. When we want to use another group of products, we can change the factory. For example:
void main(){ PicFactory* f = new GDIFactory(); // PicFactory* f = new DXFactory(); f->makePic();}
You can directly change the factory to create another product group. Careful students will surely find that,Isn't this new a violation of DIP?Yes. Is it dizzy? Indeed, many times there will always be some tangle in the design field. OK. As mentioned earlier, if DIP is strictly followed, any new line of code violates DIP. The key is to see whether the violation is related. If the target object is stable, the violation does not matter. For example, the Factory here, except for the possibility of adding a new derivative Factory, will hardly change anything else. Therefore, the violation in this area does not matter. We introduced the factory,This is because the Pic class is quite variable and the factory itself is relatively stable.In this case, the factory model can play a role.
When to introduce the factory model depends on the specific situation. A simple principle is:When the product (pic class) You want to create is relatively variable, you should consider it.
Of course, the factory model also has some disadvantages: First, it needs to create a factory class, which is a major overhead. The advantage of the factory model is that it can solve the coupling between the customer and the specific product classes and implement the DIP principle.
In fact, it is even more common that a factory can create a series of products that do not inherit from the same interface. More general situations should be as follows:
<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + Environment + CjxzdHJvbmc + tfy0 + Environment + 7G8MLrtcTS/Environment + c350rLKx7vsus/environment/LT6tcS5/environment/Environment + Environment/ LT60d2x5L + 0xvDAtL7Nz/HKx6O6PC9wPgo8cD48aW1nIHNyYz0 = "http://www.2cto.com/uploadfile/Collfiles/20140917/20140917084258267.png" alt = "">