C# 中的双向适配器和可插拔适配器模式有什么区别?

2024-03-09

双向适配器和可插入适配器都可以访问这两个类,并且还可以更改需要更改的方法的行为。以下是我的代码:

双向适配器

public interface IAircraft
{
    bool Airborne { get; }
    void TakeOff();
    int Height { get; }
}

// Target
public sealed class Aircraft : IAircraft
{
    int height;
    bool airborne;
    public Aircraft()
    {
        height = 0;
        airborne = false;
    }
    public void TakeOff()
    {
        Console.WriteLine("Aircraft engine takeoff");
        airborne = true;
        height = 200; // Meters
    }
    public bool Airborne
    {
        get { return airborne; }
    }
    public int Height
    {
        get { return height; }
    }
}
// Adaptee interface
public interface ISeacraft
{
    int Speed { get; }
    void IncreaseRevs();
}
// Adaptee implementation
public class Seacraft : ISeacraft
{
    int speed = 0;
    public virtual void IncreaseRevs()
    {
        speed += 10;
        Console.WriteLine("Seacraft engine increases revs to " + speed + " knots");
    }
    public int Speed
    {
        get { return speed; }
    }
}
// Adapter
public class Seabird : Seacraft, IAircraft
{
    int height = 0;
    // A two-way adapter hides and routes the Target's methods
    // Use Seacraft instructions to implement this one
    public void TakeOff()
    {
        while (!Airborne)
            IncreaseRevs();
    }
    // Routes this straight back to the Aircraft
    public int Height
    {
        get { return height; }
    }

    // This method is common to both Target and Adaptee
    public override void IncreaseRevs()
    {
        base.IncreaseRevs();
        if (Speed > 40)
            height += 100;
    }
    public bool Airborne
    {
        get { return height > 50; }
    }
}
class Experiment_MakeSeaBirdFly
{
    static void Main()
    {
        // No adapter
        Console.WriteLine("Experiment 1: test the aircraft engine");
        IAircraft aircraft = new Aircraft();
        aircraft.TakeOff();
        if (aircraft.Airborne) Console.WriteLine(
        "The aircraft engine is fine, flying at "
        + aircraft.Height + "meters");
        // Classic usage of an adapter
        Console.WriteLine("\nExperiment 2: Use the engine in the Seabird");
        IAircraft seabird = new Seabird();
        seabird.TakeOff(); // And automatically increases speed
        Console.WriteLine("The Seabird took off");
        // Two-way adapter: using seacraft instructions on an IAircraft object
        // (where they are not in the IAircraft interface)
        Console.WriteLine("\nExperiment 3: Increase the speed of the Seabird:");
        (seabird as ISeacraft).IncreaseRevs();
        (seabird as ISeacraft).IncreaseRevs();
        if (seabird.Airborne)
            Console.WriteLine("Seabird flying at height " + seabird.Height +
            " meters and speed " + (seabird as ISeacraft).Speed + " knots");
        Console.WriteLine("Experiments successful; the Seabird flies!");

        Console.Read();
    }
}

可插拔模式

class Adaptee
{
    public double Precise(double a, double b)
    {
        return a / b;
    }
}

// New standard for requests
class Target
{
    public string Estimate(int i)
    {
        return "Estimate is " + (int)Math.Round(i / 3.0);
    }
}    

// Implementing new requests via old
class Adapter : Adaptee
{
    public Func<int, string> Request;    
    // Different constructors for the expected targets/adaptees    
    // Adapter-Adaptee
    public Adapter(Adaptee adaptee)
    {
        // Set the delegate to the new standard
        Request = x =>
        {
            return "Estimate based on precision is " +
           (int)Math.Round(Precise(x, 3));
        };
    }

    // Adapter-Target
    public Adapter(Target target)
    {
        // Set the delegate to the existing standard
        Request = target.Estimate;
    }
}

class Client
{    
    static void Main()
    {    
        Adapter adapter1 = new Adapter(new Adaptee());
        Console.WriteLine(adapter1.Request(5));

        Adapter adapter2 = new Adapter(new Target());
        Console.WriteLine(adapter2.Request(5));    
        Console.Read();

    }
}

在上面的两个代码示例中,我没有发现模式功能方面有任何不同。那么这些模式之间有什么区别呢?谁能帮我理解它吗?我一直在参考这个设计模式 C# 3.0 http://www.kitabxana.net/files/books/file/1330505636.pdf

UPDATE 1

我无法理解本参考文献中给出的示例,我是否更新了简单的代码,并且我想根据代码从场景中实现双向适配器

 interface Ibike {
        void Ride(int energy,int time);
    }
    class Bike : Ibike {
        public void Ride(int energy,int time) {
            Console.WriteLine("riding bike with calories of energy "+energy+" spend time "+time);
        }
    }
    interface Imotorcycle {
        void Ride(int fuel);
    }
    class Motorcycle : Imotorcycle {
        public void Ride(int fuel) {
            Console.WriteLine("riding motorbike with fuel "+fuel);
        }
    }
    class Client {
        static void Main() {
            Ibike bike = new Bike();
            Imotorcycle motorBike = new Motorcycle();
            bike.Ride(50, 2);
            motorBike.Ride(3);


            Console.Read();
        }
    }

现在在这种情况下我怎样才能将其作为双向适配器。 双向适配器解决了两个系统的问题 一个系统的特性必须在另一个系统中使用,反之亦然 反之亦然。建立一个Adapter类来吸收重要的共同点 两者的方法并为两者提供适应。所结果的 适配器对象将被双方接受


所有引言均摘自C# 3.0 设计模式 https://msdn.microsoft.com/en-us/library/orm-9780596527730-01-04.aspx,这恰好是您问题的同一来源。
大胆强调引文是我的。

在双向适配器上:

适配器提供对适应者中某些行为的访问(行为 ITarget 接口中需要),但 Adapter 对象不是 可与 Adaptee 对象互换。它们不能用于以下地方 Adaptee 对象可以,因为它们致力于实现 适应者,而不是它的接口。有时我们需要有一些对象可以 是透明的 ITarget 或 Adaptee 对象。这很容易 如果 Adapter 继承了这两个类,则可以实现;然而, 这种多重继承在 C# 中是不可能的,所以我们必须看看 其他解决方案。

双向适配器解决了两个问题 系统,其中必须利用一个系统的特性 其他,反之亦然。设置一个Adapter类来吸收 两者的重要共同方法,并为两者提供适应。 生成的适配器对象将被双方接受。理论上,这个想法可以扩展到两个以上的系统,所以 我们可以有多路适配器,但有一些实现 限制:如果没有多重继承,我们必须插入一个 每个原始类和适配器之间的接口。

在这种情况下,除了调整多个系统之间的通用功能之外,我们还讨论使来自不同系统的两个(或更多)不同功能可用于在同一适配器上进行调用。在您的代码示例中:

//The adapter
IAircraft seabird = new Seabird(  );

// This is a IAircraft method
seabird.TakeOff(  ); 

//This is NOT a IAircraft method, but is made available through the adapter.
(seabird as ISeacraft).IncreaseRevs(  ); 

现在,在可插拔适配器上:

可插拔适配器的一个显着特征是 客户端调用的方法以及ITarget接口中存在的方法 可以不同。适配器必须能够处理名称更改。 在以前的适配器变体中,这对于所有适配器都是如此 方法,但客户端必须使用 ITarget 接口中的名称。 (...)

可插式适配器会分出哪个对象正在插入 时间。一旦服务被插入并且它的方法已经被 分配给委托对象,关联持续到另一个 分配了一组方法。可插拔适配器的特点是 它将为它所适应的每种类型都有构造函数。 在每一个中,它都会执行委托分配(一个或多个 如果还有其他重新路由的方法,则为一个)。

因此,这里我们有一个通用名称,可以通过该名称调用任何系统的任何插入方法,但在给定时间只能使用一个。 我认为这两种方法都会执行通过不同方式或具有不同细节级别提供相似结果的操作,但这似乎不是该模式的规则。

再次,使用您的示例:

Adapter adapter1 = new Adapter (new Adaptee(  ));
//Here, it will call the Adaptee's abstracted method. 
adapter1.Request(5);

//The only way to call the Target's method is to instantiate a new adapter with the target    
Adapter adapter2 = new Adapter (new Target(  ));
Console.WriteLine(adapter2.Request(5));

结论:

尽管所有适配器都具有通过 ITarget 使适配器可供客户端使用的相同目标,但每个适配器都针对不同的问题集提供了解决方案,无论是双向适配器使目标对适应者可用,反之亦然 or the 可插拔以原子方式抽象目标和适应者的行为.

希望这有助于消除两个适配器之间的差异。

更新 1. 有关双向的更多信息:

我可以从你的例子看出你没有明白双向适配器的目的。仅当您需要互换使用适应者和目标时才需要它,就好像您将它们不同的功能合并到单个对象中一样。
如果它们都做同样的事情(即骑行),那么您最好使用可插拔适配器。

让我们以一种使用双向适配器有意义的方式修改您的新示例。

interface IBike {
    void Pedal();
}
class Bike : IBike {
    public void Pedal() {
        Console.WriteLine("Moving my vehicle with my body");
    }
}

interface IMotorcycle {
    void Accelerate();
}
class Motorcycle : IMotorcycle {
    public virtual void Accelerate() {
        Console.WriteLine("Moving my vehicle with a hydrocarbon fuel engine");
    }
}

class ElectricBike : Motorcycle, IBike {
    bool _isAccelerating = false;

    public override void Accelerate() {
        _isAccelerating = true;
        Console.WriteLine("Moving my vehicle with a electric engine");
    }

    public void Pedal() {
        if (!_isAccelerating)
            Console.WriteLine("Moving my vehicle with my body");
        else
            Console.WriteLine("Occupying my body with senseless effort, for my vehicle is already moving"); 
    }        
}

class MovingMyVehicle {
    static void Main() {
        IMotorcycle motorBike = new Motorcycle();
        //That is expected, as IMotorcycle can Accelerate.
        motorBike.Accelerate();

        IBike newBike = new ElectricBike();
        //That too is expected, as IBike can Pedal.
        newBike.Pedal();

        //Now that´s something new, as IBike cannot Accelerate, 
        //but the the ElectricBike adapter can, as it implements both interfaces.
        (newBike as IMotorcycle).Accelerate();

        Console.Read();
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 中的双向适配器和可插拔适配器模式有什么区别? 的相关文章

  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • 对类 static constexpr 结构的未定义引用,g++ 与 clang

    这是我的代码 a cp p struct int2 int x y struct Foo static constexpr int bar1 1 static constexpr int2 bar2 1 2 int foo1 return
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • 两个静态变量同名(两个不同的文件),并在任何其他文件中 extern 其中一个

    在一个文件中将变量声明为 static 并在另一个文件中进行 extern 声明 我认为这会在链接时出现错误 因为 extern 变量不会在任何对象中看到 因为在其他文件中声明的变量带有限定符 static 但不知何故 链接器 瑞萨 没有显
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐

  • 如何进行这种图像转换?

    我有一个带有模糊边缘的彩色斑点的图像 上半部分 我想为其创建一个由直线组成的轮廓 下半部分 填充形状没有问题 只需添加轮廓即可 如有必要 可以将其转换为黑白图像 谁能指出一个可以做到这一点的简单转换 程序 最好是我可以轻松找到代码示例的东西
  • 如何获取与正则表达式匹配的片段的行号?

    如何才能获得行号匹配给定的所有文本片段regexp 在一个文件内 file content f read m re compile regexp How to extract line numbers of the matched text
  • 如何使用 Django 和 UTF-8 内容类型作为模板?

    当我做 return render to response 在姜戈 如何将内容类型设置为 UTF 8 那么显示的所有内容都是 UTF 8 吗 django 使用 UTF 8 作为默认编码 但这可以通过 settings DEFAULT CH
  • Angular 2 动态双向绑定

    我正在尝试构建一个动态附加另一个组件的组件 作为一个例子 这是我的父类 import Component ComponentRef ViewChild ViewContainerRef ComponentFactoryResolver fr
  • 需要使用 Node.js 进行 SysLog 的建议

    我刚刚 npm install node syslog 但它不起作用 我有一个系统日志服务器 IP 地址和 local0 我正在寻找一个系统日志模块来帮助我将消息发布到系统日志 但我不知道我应该使用哪一个 请给我一些建议 谢谢 哦 如果有一
  • 如何防止Ktor客户端对url参数进行编码?

    我正在尝试使用 kotlin 创建一个 Android 应用程序 这个应用程序需要有一个迷你下载管理器 因为我需要下载从 100MB 到 8GB 的 文件 并且当服务器支持暂停时 用户可以稍后暂停和恢复下载 搜索我发现了Ktor 库并阅读文
  • 如何让 Unirest(java) 忽略证书错误

    我正在使用 Unirest java 版本 发出 GET 和 POST 请求 但是在访问 SSL 加密站点时遇到问题 因为我的程序位于公司网络后面 并且网络管理员为我设置了防火墙映射 例如foobar com被映射到56 1 89 12 4
  • 在php中获取远程图像的图像类型

    使用预构建的系统来抓取远程图像并将其保存到服务器上 目前 没有检查图像是否确实存在于该远程位置 并且它具有某种文件类型 jpg jpeg gif 我的任务是执行这两项操作 我认为这非常简单 因为我只需使用一个简单的正则表达式和 getima
  • 如何访问静态 Web 方法内的页面控件? [复制]

    这个问题在这里已经有答案了 我已经使用 jQuery 使用静态调用了代码隐藏方法WebMethod method 该 Web 方法调用成功 但当尝试访问文本框控件时出现错误 非静态字段 方法或属性需要对象引用 WebMethod publi
  • Django:动态构造 {% include %} 标签的值?

    我想用一个 include page html 在我的 Django 模板中标记 并构造值page html动态地 在 Django 中有什么方法可以做到这一点吗 这是一个伪代码示例 include page mode html Thank
  • 如何将 jar、源代码和 Javadoc 添加到本地 Maven 存储库?

    我想添加最新版本的 JGoodies Forms 1 5 0 作为依赖项 但我在主存储库中找不到比 1 0 5 更新的任何内容 所以如果我理解正确 我可以做的下一个最好的事情要做的就是将其添加到我的本地存储库中 当我从网站下载它时 我得到一
  • 使用 React 进行变更检测

    我正在研究更改检测机制 并且在reactjs案例中遇到了一些麻烦 当反应组件中的 props 发生变化时 该组件将被 重新渲染 由于 diff 算法的原因 这并不完全正确 但想法就在这里 我知道当某物发生这种情况时 React 会浏览其内部
  • 如何让 Rails 为 ember.js 生成正确格式的 JSON?

    在 Ember 模型指南中http emberjs com guides models the rest adapter toc relationships http emberjs com guides models the rest a
  • DialogFragment 按钮被推出屏幕 API 24 及更高版本

    我正在定制DialogFragment显示可选择的数据列表 该列表太长 无法在不滚动的情况下显示在屏幕上 对于 API 23 及以下版本 一切似乎都工作正常 但当我在 API 24 上进行测试时 DialogFragment 的按钮不再可见
  • 从 Firebase 数据库获取的数据显示在 3 个单独的警报对话框中,而不是一个

    我正在从中获取一些数据FirebaseDatabase然后将它们放入array然后尝试以List这是一个习惯AlertDialog 这是代码 query mDatabase child child child anotherChild ch
  • Spring MVC 4:“application/json”内容类型未正确设置

    我有一个使用以下注释映射的控制器 RequestMapping value json method RequestMethod GET produces application json ResponseBody public String
  • 如何强制删除Python对象?

    我很好奇的细节 del 在 python 中 何时 为什么应该使用它以及不应该使用它 我经历了惨痛的教训才知道 它并不像人们天真地期望的析构函数那样 因为它并不是与 new init class Foo object def init se
  • Jquery中动态选择Drop Down

    我有 4 个下拉菜单 默认情况下 每个 drop 都有一个 select 选项 每个盒子都有一个唯一的 ID 如您所见 如果上面的下拉列表值为 select 则禁用第二个下拉列表 仅当该值不是 select 时才会启用 这是我的代码 doc
  • Java ImageIO.read 导致 OSX 挂起

    我必须在 Mac OSX 上读取图像时执行一些操作 但是在调用 ImageIO read File 时它似乎挂起 似乎也没有出现堆栈跟踪 它实际上只是挂起 想知道其他人是否遇到过这个问题 我已经成功地写了一张图片 只是阅读方面似乎有问题 使
  • C# 中的双向适配器和可插拔适配器模式有什么区别?

    双向适配器和可插入适配器都可以访问这两个类 并且还可以更改需要更改的方法的行为 以下是我的代码 双向适配器 public interface IAircraft bool Airborne get void TakeOff int Heig