[design mode] wrapper mode: adapter mode
KunQAQrz 2021-06-04 09:47:50

Intention

Adapter pattern Enables objects with incompatible interfaces to cooperate with each other .
 Let the car run on the track

problem

If you're using C++ Develop a program , In the development process, we need to use a series of C Functions written in language , You need to pass a class into these functions . and C Languages don't support the concept of classes ,C Language implementation class , You can only simulate classes with structs .
For the user experience , You still want users to use C++ Class in , Instead of using classes simulated by structs . But if you take that series C Function reuse C++ Do it again , It's going to be a lot of work .

Solution

You can create an adapter , This is a special object , Can transform object interfaces , Enable it to interact with other objects . The adapter pattern hides the complex transformation process behind the scenes by encapsulating objects , The encapsulated object is not even aware of the adapter .
In the question just now, you can see the following figure , In class and C Add an adapter in the middle of the function , Through the transfer function , Convert classes to structs . Because the adapter inherits from the struct , So you can pass the adapter as a structure directly into C Function . When you need to call a struct method , Through m_class This member variable accesses the functions of the class .

Sample code

Here are AWTK-MVVM Part of the sample code using the adapter :

/* temperature_validator.cpp */
#include "temperature_validator.hpp"
#include "mvvm/cpp/adapter.hpp"
class TemperatureValidator : public vm::ValueValidator {

public:
virtual bool_t IsValid(const value_t* value, str_t* msg) {

int32_t temp = value_int(value);
if (temp <= 20) {

str_set(msg, "too low");
return FALSE;
} else if (temp >= 60) {

str_set(msg, "too high");
return FALSE;
} else {

str_set(msg, "normal");
return TRUE;
}
}
virtual ret_t Fix(value_t* value) {

return RET_OK;
}
};
static void* create_water_temp_validator(void) {

/* class Convert to struct */
return vm::To(new TemperatureValidator());
}
ret_t temperature_validator_init(void) {

value_validator_register("water_temp", create_water_temp_validator);
return RET_OK;
}
/* value_validator.c */
/* C function */
ret_t value_validator_register(const char* name, tk_create_t create) {

return_value_if_fail(name != NULL, RET_BAD_PARAMS);
return_value_if_fail(create != NULL && s_validator_factory != NULL, RET_BAD_PARAMS);
return object_set_prop_pointer(s_validator_factory->creators, name, create);
}
/* value_validator.h */
/** * @class value_validator_t * @parent object_t * * Value checker . * * The type entered by the user on the interface may be invalid ,value_validator Responsible for checking the validity of user input . * */
struct _value_validator_t {

object_t object;
object_t* context;
/*private*/
value_validator_is_valid_t is_valid;
value_validator_fix_t fix;
}value_validator_t;
/* adapter.cpp */
namespace vm {

static object_vtable_t s_value_validator_adapter_vtable;
typedef struct _value_validator_adapter_t {

/* Inherit : value_validator_adapter_t -> value_validator_t -> object_t */
value_validator_t value_validator;
/*private*/
ValueValidator* cpp;
} value_validator_adapter_t;
static ret_t value_validator_adapter_init_vtable(object_vtable_t* vt) {

vt->type = "value_validator_adapter";
vt->desc = "value_validator_adapter";
vt->size = sizeof(value_validator_adapter_t);
vt->is_collection = FALSE;
return RET_OK;
}
#define VALUE_VALIDATOR_ADAPTER(obj) ((value_validator_adapter_t*)(obj))
static bool_t value_validator_adapter_is_valid(value_validator_t* c, const value_t* value,
str_t* msg) {

value_validator_adapter_t* value_convert_adapter = VALUE_VALIDATOR_ADAPTER(c);
/* call class function */
return value_convert_adapter->cpp->IsValid(value, msg);
}
static ret_t value_validator_adapter_fix(value_validator_t* c, value_t* value) {

value_validator_adapter_t* value_convert_adapter = VALUE_VALIDATOR_ADAPTER(c);
return value_convert_adapter->cpp->Fix(value);
}
value_validator_t* value_validator_cpp_create(ValueValidator* cpp) {

object_t* obj = NULL;
value_validator_t* value_convert = NULL;
return_value_if_fail(cpp != NULL, NULL);
value_validator_adapter_t* value_convert_adapter = NULL;
value_validator_adapter_init_vtable(&s_value_validator_adapter_vtable);
obj = object_create(&s_value_validator_adapter_vtable);
return_value_if_fail(obj != NULL, NULL);
value_convert = VALUE_VALIDATOR(obj);
value_convert->fix = value_validator_adapter_fix;
value_convert->is_valid = value_validator_adapter_is_valid;
value_convert_adapter = VALUE_VALIDATOR_ADAPTER(obj);
value_convert_adapter->cpp = cpp;
return value_convert;
}
value_validator_t* To(ValueValidator* cpp) {

return value_validator_cpp_create(cpp);
}
} // namespace vm

Adapter pattern structure

Object adapter

Using the principle of composition : The adapter implements the interface to one of the objects , And encapsulate another object .
The above example code uses the object adapter .

characteristic

  • When Service Class is more complex , Construct a Service Class objects are difficult .
  • stay Service Class adds abstract methods ,Adapter Class does not need to be modified , It can also be used normally .
  • You can use polymorphism in Adapter In the class Service Subclass method .
     Object adapter URL chart

The class adapter

Using the inheritance mechanism : The adapter inherits the interface of both objects .
characteristic

  • Adapter Direct class inheritance Service class , Can be in Adapter Class Service Class .
  • stay Service Class adds abstract methods ,Adapter Class also needs to be changed , High code coupling .
  • If Service Class has other subclasses ,Adapter Cannot be called in the class Service Subclass method . The class adapter URL chart

summary

Adapter mode structure selection

Try to use low coupling object adapters , Use less class adapters , Avoid multiple inheritance . But if the construction Service When the object is very difficult , Consider using class adapters .

Suitable for application scenarios

  • When you want to use a class , But when its interface is not compatible with other code , You can use adapter classes .
  • If you need to reuse these classes , They are in the same inheritance system , And they have some extra common methods ,
    But these common methods are not common to all subclasses in this inheritance system .
     Insert picture description here

advantage

  • Opening and closing principle , As long as the client code interacts with the adapter through the client interface , You can add a new type of adapter to your program without modifying the existing client code .
  • Principle of single responsibility , Separate the interface or data conversion code from the main business logic of the program .

shortcoming

  • The overall complexity of the code increases , Because you need to add a series of interfaces and classes . Sometimes it's easier to change the service class directly to make it compatible with other code .

Reference resources

22 Design patterns :refactoringguru.cn/design-patterns
AWTK:github.com/zlgopen/awtk
《 Design patterns : The foundation of reusable object-oriented software 》

Please bring the original link to reprint ,thank
Similar articles

2021-08-09

2021-08-09