12設計パターン_訪問者パターン_ C言語の実装

訪問者モード

1シミュレーションシーン

ネットワークポートドライバーを開発するとします。ネットワークポートには、低速ネットワークポートと高速ネットワークポートの2種類があります。各タイプのネットワークポートは、構成レートと構成モードの操作をサポートしています。すると、ドライバーは次のようになります。

ここに画像の説明を挿入

上記の手順が実装されていると仮定すると、今はビジネスニーズのため、クエリレート操作を追加する必要があります。

次に、実装されたMacクラスとそのサブクラスを変更し、MacクラスとそのサブクラスにGetSpeed()を追加する必要があります。変更されたドライバーは次のとおりです。

ここに画像の説明を挿入

この変更は明らかに「開閉の原則」に違反しています。

GetSpeed()をMacクラスとそのサブクラスに変更せずに追加する方法はありますか?

ビジターモデルはそのような方法を提供します。

もちろん、ビジターモデルを使用するための前提条件が必要です。つまり、Macクラスを設計するとき、将来的にMacクラスに操作を追加する可能性があることを予測し、実行時に操作を動的に追加するための共通インターフェイスを予約する必要があります。

最初からビジターパターンから始めましょう。

2訪問者モードの概要

GoFによって提供されるビジターパターンの目的は、オブジェクト構造の各要素に作用する操作を表すことです。つまり、各要素のクラスを変更せずに、これらの要素に作用する新しい操作を定義できます。

上記のシナリオに固有:各要素はMacクラスとそのサブクラスです。新しい操作はGetSpeed()です。

新しいオペレーションをVisitorとして定義し、新しいオペレーションが追加されるたびにVisitorのサブクラスを追加します。

Macクラスを定義するとき、実行時に動的に操作を追加するための一般的なインターフェイスAccept(Visitor)を予約する必要があります。Acceptは新しいオペレーションを受け取ることができます。このようにして、後で追加される新しい操作の数に関係なく、新しい操作をAcceptを介してMacに適用できます。

ビジターパターンの特定の実装を見てみましょう。

3ビジターモードを使用してネットワークポートドライバーを実装する

参加者

  1. ビジター

訪問者がアクセスできる要素を宣言し、アクセス可能な要素ごとに訪問者操作を宣言します。

上記のシナリオでは、HighSpeedMacとLowSpeedMacの2つのアクセス可能な要素があります。したがって、HighSpeedMacおよびLowSpeedMacに対して、Visitor操作VisitLowSpeedMac()およびVisitHignSpeedMac()をそれぞれ宣言する必要があります。

  1. ConcreteVisitor:GetSpeedVisitor

訪問者が宣言した操作を実装します。操作が追加されるたびに、ConcreteVisitorを追加する必要があります。

例としてGetSpeed()の追加を見てみましょう。後でGetMode()を追加する必要がある場合は、もう一度GetModeVisitorを定義するだけで済みます。

  1. 要素:Mac

実行時に動的に操作を追加するための一般的なインターフェースAcceptを予約する必要があります

  1. ConcreteElement:LowSpeedMac、HighSpeedMac

ConcreteElement自体のメソッドとAcceptを実現します。

  1. ObjectStruct

Elementを列挙するためのインターフェースを提供します。この例では、例として2つの要素のみを定義するため、特別なObjectStructを定義せずに、メイン関数に直接要素をリストします。

UML

ここに画像の説明を挿入

訪問者サンプルコード

visitor.h

#ifndef VISITOR_H
#define VISITOR_H

#include "mac.h"

struct Visitor {
    void (*VisitLowSpeedMac)(struct Visitor *this, struct Mac *lowSpeedMac);
    void (*VisitHighSpeedMac)(struct Visitor *this, struct Mac *highSpeedMac);
};

#endif

GetSpeedVisitorサンプルコード

get_speed_visitor.h

#ifndef GET_SPEED_VISITOR_H
#define GET_SPEED_VISITOR_H

#include "visitor.h"

// 构造函数
void GetSpeedVisitor(struct Visitor *this);

// 析构函数
void _GetSpeedVisitor(struct Visitor *this);

#endif

get_speed_visitor.c

#include "get_speed_visitor.h"
#include <stddef.h>
#include <stdio.h>

static void VisitLowSpeedMac(struct Visitor *this, struct Mac *lowSpeedMac)
{
    printf("  get speed for low speed mac, speed is \"%s\"\n", lowSpeedMac->speed);
}

static void VisitHighSpeedMac(struct Visitor *this, struct Mac *highSpeedMac)
{
    printf("  get speed for high speed mac, speed is \"%s\"\n", highSpeedMac->speed);
}

// 构造函数
void GetSpeedVisitor(struct Visitor *this)
{
    this->VisitLowSpeedMac = VisitLowSpeedMac;
    this->VisitHighSpeedMac = VisitHighSpeedMac;
}

// 析构函数
void _GetSpeedVisitor(struct Visitor *this)
{
    this->VisitLowSpeedMac = NULL;
    this->VisitHighSpeedMac = NULL;
}

Macサンプルコード

mac.h

#ifndef MAC_H
#define MAC_H

#include "visitor.h"

struct Mac {
    char mode[50];
    char speed[50];
    // 编译时已实现的操作
    void (*SetMode)(struct Mac *this, char *mode);
    void (*SetSpeed)(struct Mac *this, char *speed);
    // 用于在运行时扩展操作
    void (*Accept)(struct Mac *this, struct Visitor *visitor);
};

#endif

LowSpeedMacサンプルコード

low_speed_mac.h

#ifndef LOW_SPEED_MAC_H
#define LOW_SPEED_MAC_H

#include "mac.h"

// 构造函数
void LowSpeedMac(struct Mac *this);

// 析构函数
void _LowSpeedMac(struct Mac *this);

#endif

low_speed_mac.c

#include "low_speed_mac.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h> 

static void SetMode(struct Mac *this, char *mode)
{
    strcpy(this->mode, mode);
    printf("  set mode for low speed mac, mode is \"%s\"\n", mode);
}

static void SetSpeed(struct Mac *this, char *speed)
{
    strcpy(this->speed, speed);
    printf("  set speed for low speed mac, speed is \"%s\"\n", speed);
}

static void Accept(struct Mac *this, struct Visitor *visitor)
{
    visitor->VisitLowSpeedMac(visitor, this);
}

// 构造函数
void LowSpeedMac(struct Mac *this)
{
    this->mode[0] = 0;
    this->speed[0] = 0;
    this->SetMode = SetMode;
    this->SetSpeed = SetSpeed;
    this->Accept = Accept;
}

// 析构函数
void _LowSpeedMac(struct Mac *this)
{
    this->mode[0] = 0;
    this->speed[0] = 0;
    this->SetMode = NULL;
    this->SetSpeed = NULL;
    this->Accept = NULL;
}

HighSpeedMacサンプルコード

high_speed_mac.h

#ifndef HIGH_SPEED_MAC_H
#define HIGH_SPEED_MAC_H

#include "mac.h"

// 构造函数
void HighSpeedMac(struct Mac *this);

// 析构函数
void _HighSpeedMac(struct Mac *this);

#endif

high_speed_mac.c

#include "high_speed_mac.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h> 

static void SetMode(struct Mac *this, char *mode)
{
    strcpy(this->mode, mode);
    printf("  set mode for high speed mac, mode is \"%s\"\n", mode);
}

static void SetSpeed(struct Mac *this, char *speed)
{
    strcpy(this->speed, speed);
    printf("  set speed for high speed mac, speed is \"%s\"\n", speed);
}

static void Accept(struct Mac *this, struct Visitor *visitor)
{
    visitor->VisitHighSpeedMac(visitor, this);
}

// 构造函数
void HighSpeedMac(struct Mac *this)
{
    this->mode[0] = 0;
    this->speed[0] = 0;
    this->SetMode = SetMode;
    this->SetSpeed = SetSpeed;
    this->Accept = Accept;
}

// 析构函数
void _HighSpeedMac(struct Mac *this)
{
    this->mode[0] = 0;
    this->speed[0] = 0;
    this->SetMode = NULL;
    this->SetSpeed = NULL;
    this->Accept = NULL;
}

クライアントコードの例

#include "low_speed_mac.h"
#include "high_speed_mac.h"
#include "get_speed_visitor.h"
#include <stdio.h>

void main()
{
    struct Mac lowSpeedMac;
    LowSpeedMac(&lowSpeedMac);
    struct Mac highSpeedMac;
    HighSpeedMac(&highSpeedMac);

    printf("调用低速网口编译时已实现的操作:\n");
    lowSpeedMac.SetSpeed(&lowSpeedMac, "1G");
    lowSpeedMac.SetMode(&lowSpeedMac, "GMII");
    printf("\n");
    printf("调用高速网口编译时已实现的操作:\n");
    highSpeedMac.SetSpeed(&highSpeedMac, "50G");
    highSpeedMac.SetMode(&highSpeedMac, "SGMII");
    printf("\n");
   
    printf("--扩展getSpeed操作--\n");
    printf("\n");
    struct Visitor getSpeedVisitor;
    GetSpeedVisitor(&getSpeedVisitor);
    printf("调用低速网口运行时扩展的操作:\n");
    lowSpeedMac.Accept(&lowSpeedMac, &getSpeedVisitor);
    printf("\n");
    printf("调用高速网口运行时扩展的操作:\n");
    highSpeedMac.Accept(&highSpeedMac, &getSpeedVisitor);
    printf("\n");
}

クライアントの表示例

-bash-4.2# ./test
调用低速网口编译时已实现的操作:
  set speed for low speed mac, speed is "1G"
  set mode for low speed mac, mode is "GMII"

调用高速网口编译时已实现的操作:
  set speed for high speed mac, speed is "50G"
  set mode for high speed mac, mode is "SGMII"

--扩展getSpeed操作--

调用低速网口运行时扩展的操作:
  get speed for low speed mac, speed is "1G"

调用高速网口运行时扩展的操作:
  get speed for high speed mac, speed is "50G"

4ビジターモードの使用に関する制限

制限:

前の説明で制限の1つを述べました。要素を設計するときに、将来的に要素に操作が追加される可能性があることを想定し、実行時に動的に操作を追加するための一般的なインターフェイス、つまりAccept()を予約しました。

制限2:

また、より厳しい制限もあります。Elementのサブクラスの数は、安定している必要があります。

ビジターでは、各要素(つまり、Elementの各サブクラス)に対してビジターオペレーションを宣言する必要があるためです。したがって、Elementのサブクラスを追加するときは、Visitorの定義を変更して新しいVisitor操作を追加する必要があります。これは明らかに「開閉の原則」に違反しています。

したがって、注意してください:この記事のシナリオでは、MacにはLowSpeedMacとHighSpeedMacの2つのサブカテゴリしかないと想定しています。これはより厳しい制限です。実際には、Macのサブカテゴリは安定していません。これは、将来SuperHighSpeedMacを追加する必要がある可能性が非常に高いためです。この場合、ビジターモデルは適用されません。

おすすめ

転載: blog.csdn.net/weixin_46826913/article/details/107751534