首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C#中,双向适配器和可插拔适配器模式有什么区别?

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

Stack Overflow用户
提问于 2016-11-01 17:36:08
回答 1查看 1.8K关注 0票数 4

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

双向适配器

代码语言:javascript
复制
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();
    }
}

可插拔模式

代码语言:javascript
复制
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

更新1

我无法理解在这个参考中给出的例子,所以我更新了一个简单的代码,我想基于代码实现场景中的双向适配器。

代码语言:javascript
复制
 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类是为了吸收两者的重要通用方法,并为两者提供适应性。产生的适配器对象对双方都是可接受的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-11-18 22:49:36

C# 3.0设计模式中提取的所有引号,恰好都是您问题的来源。

我的报价是大胆的emphasys。

双向适配器上的

适配器提供对适配器中某些行为的访问( ITarget接口中所需的行为),但是Adapter对象不能与适配器对象互换。它们不能在适配器对象可以使用的地方使用,因为它们处理的是适配器的实现,而不是它的接口。有时我们需要有可以透明地ITarget或自适应对象的对象。如果Adapter继承了这两个类,这很容易实现;但是,在C#中不可能实现这种多重继承,因此我们必须考虑其他解决方案。双向适配器解决了两个系统的问题,其中--一个系统的特性必须在另一个系统中使用,反之亦然。建立一个Adapter类是为了吸收两者的重要通用方法,并为两者提供适应性。从理论上讲,这种思想可以扩展到两个以上的系统,这样我们就可以有多路适配器,但也有一些实现上的限制:如果没有多重继承,我们必须在每个原始类和适配器之间插入一个接口。

在本例中,除了调整多个系统之间的公共功能之外,我们还在讨论如何使来自不同系统的两个(或更多)不同功能可用于调用同一个适配器。在您的代码示例中:

代码语言:javascript
复制
//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接口中的名称。 可插拔适配器()对正在插入的对象进行排序。一旦将服务插入并将其方法分配给委托对象,关联就会持续到分配了另一组方法为止。可插拔适配器的特点是它将为其所适应的每种类型设置构造函数。在其中的每一个中,它都执行委托分配(如果有更多的重路由方法,则一个或多个)。

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

同样,使用您的示例:

代码语言:javascript
复制
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向客户端提供适配器的相同要求,但每个适配器都为不同的问题提供了解决方案,无论是双向适配器,使目标都可用于适配器,反之亦然的,还是以原子方式抽象目标和适配器行为的。

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

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

我可以从你的例子中看出,你没有达到双向适配器的目的。只有在需要交替地使用适配器和目标时,才需要这样做,就好像您要将它们的不同功能合并到一个对象中一样。

如果他们都做同样的事情(也就是骑自行车),你最好用一个可插拔适配器代替。

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

代码语言:javascript
复制
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();
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40365488

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档