The schema definition

The Adapter Pattern preserves the functionality of existing classes, but is responsible for transforming one type of interface into the desired one for another type of developer. It also has another name, Wapper.

Demand scenarios

Use real world examples. The most typical reference object of the adapter pattern in real life is the power adapter. For example, the standard voltage of the United States and Japan is 110V, while that of China is 220V. Through the power adapter, you can convert the local power supply into the voltage required by your own equipment.

This example fits the profile of the problem the adapter is trying to solve:

  1. We need to solve the problem using existing modules. (Local power supply)
  2. The interface provided by the existing module does not meet the interface standards we are developing. (Voltage inconsistency)
  3. We designed an adapter that changed the interface standard to the one we needed. (110 v to 220 v)
  4. The adapter we designed is responsible for interface conversion and does not change the functionality of the original module if necessary. (Power supply is the same power supply)

The development case

As mobile developers, a typical example of an adaptor we encounter in development is the AD SDK adapter.

In the mobile development space, developers tend to generate AD revenue through SDKS connected to AD platforms in order to generate revenue.

There are many advertising platforms, such as Google’s Admob, Tencent’s YouTube, And Facebook’s Audience Network.

For developers, if they want to insert an AD in their app, from the developer’s point of view, it’s just a matter of calling an interface that displays an AD, regardless of whether it’s from Admob or an advertiser.

However, the SDKS provided by major advertisers are not uniform, such as AD engine initialization, pop-up full screen ads and other logic, each has its own design scheme. At this point, we need an adapter to adapt the advertising API of each platform to our own interface.

Starting from an example, we design an abstract class for advertising display AbstractAdsAdapter.

class AbstractAdsAdapter {
    // Load ads
    func load(a) {}
    // Display ads
    func showInterstitial(a){}}Copy the code

Through the abstract class, design concrete subclass AdmobAdsAdapter.

class AdmobAdsAdapter: AbstractAdsAdapter {
    override func initializeEngine(a) {
        print("Call Admob to initialize engine interface")}override func load(a) {
        print("Interface to call Admob to load ads API")}override func showInterstitial(a) {
        print("Interface to call Admob's display advertising API.")}}Copy the code

In this way, the details of the Admob call implementation are handled by the AdmobAdsAdapter.

If we also receive the general ads, then design a new subclass TencentAdsAdapter.

class TencentAdsAdapter: AbstractAdsAdapter {
    override func initializeEngine(a) {
        print("Call wide point pass initialization engine interface")}override func load(a) {
        print("Interface for invoking the AD Loading API")}override func showInterstitial(a) {
        print("Interface to invoke broadcom display advertising API")}}Copy the code

Next, to complete the invocation of the advertising module, we provide an advertising manager class.

class AdsManager {
    enum Engine: String {
        case admob, tencent
    }
    private var map: [String: AbstractAdsAdapter] = [:]
    
    func initialize(_ engine: Engine) {
        var adapter: AbstractAdsAdapter?
        switch engine {
        case .admob :
            adapter = AdmobAdsAdapter(a)case .tencent :
            adapter = TencentAdsAdapter()}if adapter ! = nil {
            map[engine.rawValue] = adapter
            adapter!.initializeEngine()
        }
    }
    
    func load(engine: Engine) {
        if let adapter = map[engine.rawValue] {
            adapter.load()
        } else {
            print(Advertising engine\(engine.rawValue)Uninitialized")}}func showInterstitial(engine: Engine) {
        if let adapter = map[engine.rawValue] {
            adapter.showInterstitial()
        } else {
            print(Advertising engine\(engine.rawValue)Uninitialized")}}}Copy the code

The manager class provides an enumeration type Engine, and when we specify the corresponding Engine, the manager class invokes the corresponding advertising module.

The test code is as follows

class AdsManager {
    enum Engine: String {
        case admob, tencent
    }
    private var map: [String: AbstractAdsAdapter] = [:]
    
    func initialize(_ engine: Engine) {
        var adapter: AbstractAdsAdapter?
        switch engine {
        case .admob :
            adapter = AdmobAdsAdapter(a)case .tencent :
            adapter = TencentAdsAdapter()}if adapter ! = nil {
            map[engine.rawValue] = adapter
            adapter!.initializeEngine()
        }
    }
    
    func load(engine: Engine) {
        if let adapter = map[engine.rawValue] {
            adapter.load()
        } else {
            print(Advertising engine\(engine.rawValue)Uninitialized")}}func showInterstitial(engine: Engine) {
        if let adapter = map[engine.rawValue] {
            adapter.showInterstitial()
        } else {
            print(Advertising engine\(engine.rawValue)Uninitialized")}}}Copy the code

The AD manager class holds the initialized AD adapter through a container map, and then also provides and implements interfaces to load and display ads. If an AD adapter is not initialized, it will not be put into the map, and calls to other interfaces will fail.

Call code tests.

let adsManager = AdsManager()
adsManager.initialize(.admob)
adsManager.load(engine: .admob)
adsManager.showInterstitial(engine: .admob)
adsManager.showInterstitial(engine: .tencent)
Copy the code

Print the output.

Call Admob initialization engine interface call Admob display AD API interface Tencent is not initializedCopy the code

The sample code for the AD adapter is enough here, although there is still a lot to add to the framework in real project development, such as error handling. But the entire model is still based on adapters.

The above sample code can be downloaded on my Github, you can poke it here, or go to github.com/FengHaiTong… .