4

Both Two-way Adapter and Pluggable Adapter can access both the classes and also change the behavior of the method which is required to be changed. The following is my code:

Two-Way Adapter

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();
    }
}

Pluggable Pattern

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();

    }
}

In the above two code samples, I don't find anything different in respect of the patterns' functionality. So what is the difference between the patterns? Can anyone help me understand it? I have been refering to this Design Pattern C# 3.0

UPDATE 1

I couldnt understand the example given in this refrence, so i have updated a simple code, and i want to implement Two-Way adapter from the scenaerio based on the code

 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();
        }
    }

Now in this scenario how can i make it as a Two-way Adapter. The two-way adapter addresses the problem of two systems where the characteristics of one system have to be used in the other, and vice versa. An Adapter class is set up to absorb the important common methods of both and to provide adaptations to both. The resulting adapter objects will be acceptable to both sides

Lijin Durairaj
  • 4,910
  • 15
  • 52
  • 85
  • 1
    Interfaces. Pluggable, you don't have to have an interface or a concrete type. Your Pluggable adapter could take in delegates instead of classes if you wanted. The MSDN code you have here is just one way the Pluggable adapter could be created based on my research. – TyCobb Nov 01 '16 at 18:16
  • @TyCobb i couldnt understand on what you said.Now, insteda of delegates if i use adaptee.Precise(x,3) to call the method then will it be called as Two-Way Adapter instead of Pluggable Adapter? – Lijin Durairaj Nov 01 '16 at 18:26
  • 1
    No. Pluggable can take in anything needed to do what it needs (classes, interfaces, delegates, etc.). Two-Way uses interfaces. With Two-way you are are defining a contract that it can leverage. Pluggable, you can just give it exactly what it needs like a method that just adds two numbers together -- you wouldn't need an entire object/interface for that. – TyCobb Nov 01 '16 at 18:35
  • @TyCobb from the first example if i call the IncreaseRevs() method using a delegate will it be a Pluggable Adapter then? – Lijin Durairaj Nov 01 '16 at 18:41
  • You should consider citing the [C# 3.0 Design Patterns](https://msdn.microsoft.com/en-us/library/orm-9780596527730-01-04.aspx) book as your source. It would probably be usefull and help others to answer your question by having access to the book's full content. – Gabriel Rainha Nov 18 '16 at 21:57
  • @GabrielRainha this is the book i have been refering http://www.kitabxana.net/files/books/file/1330505636.pdf. it is the same book which you have mentioned !!! – Lijin Durairaj Nov 18 '16 at 22:14
  • @LijinJohn Add it to the question. It will help other people in their effort to answer it. – Gabriel Rainha Nov 18 '16 at 22:51

1 Answers1

3

All quotes extracted from the C# 3.0 Design Patterns, which happens to be same source of your question.
Bold emphasys on the quotatios are on me.

On two-way adapters:

Adapters provide access to some behavior in the Adaptee (the behavior required in the ITarget interface), but Adapter objects are not interchangeable with Adaptee objects. They cannot be used where Adaptee objects can because they work on the implementation of the Adaptee, not its interface. Sometimes we need to have objects that can be transparently ITarget or Adaptee objects. This could be easily achieved if the Adapter inherited both from both classes; however, such multiple inheritance is not possible in C#, so we must look at other solutions.

The two-way adapter addresses the problem of two systems where the characteristics of one system have to be used in the other, and vice versa. An Adapter class is set up to absorb the important common methods of both and to provide adaptations to both. The resulting adapter objects will be acceptable to both sides. Theoretically, this idea can be extended to more than two systems, so we can have multiway adapters, but there are some implementation limitations: without multiple inheritance, we have to insert an interface between each original class and the adapter.

In this case, on top of adapting common functionality between multiple systems, we are talking about making two (or more) distinct functionalities from distinct systems available for the calling on the same adapter. In your code sample:

//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(  ); 

Now, on pluggable adapters:

A distinguishing feature of pluggable adapters is that the name of a method called by the client and that existing in the ITarget interface can be different. The adapter must be able to handle the name change. In the previous adapter variations, this was true for all Adaptee methods, but the client had to use the names in the ITarget interface. (...)

The pluggable adapter sorts out which object is being plugged in at the time. Once a service has been plugged in and its methods have been assigned to the delegate objects, the association lasts until another set of methods is assigned. What characterizes a pluggable adapter is that it will have constructors for each of the types that it adapts. In each of them, it does the delegate assignments (one, or more than one if there are further methods for rerouting).

So here we have a common name by which any plugged method of any system could by called, but only one can be used at a given time. I supose it would be expected that both methods perform operations that delivers similar results through different means or with distinct detail levels, but that does not seem to be a rule for the pattern.

Again, using your sample:

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));

Conclusion:

Even though all adapters share the same objetive of making a Adaptee available to a Client through a ITarget, each one offers a solution for a different set of problems, be it the Two-way adapter making both Target available to Adaptee and vice-versa or the Pluggable abstracting the behavior of both Target and Adaptee in an atomic manner.

Hope that helps clearing out the difference between the two adapters.

Update 1. More on Two-way:

I can tell by your example that you did not get the purpose of the Two-way adapter. It is required only when you need to use both the Adaptee and the Target interchangeably, as if you were merging their distinct functionalities into a single object.
If they both do the same thing (that is, Ride), you would be better off using a Pluggable Adapter instead.

Let's revamp your new sample in a way that it makes sense to use a Two-way adapter.

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();
    }
}
Gabriel Rainha
  • 1,713
  • 1
  • 21
  • 34
  • what if the adaptee doesnt have an interface, is it not possible then to have a two-way adapter? what if a former coder has implemented a method which doenot have a contract of an interface, then? – Lijin Durairaj Nov 18 '16 at 23:31
  • i couldnt understand the example given C# 3.0 Design Patterns, thats the reason i have raised the question. I have updated a simple example in my question, please have a look and help me understand – Lijin Durairaj Nov 18 '16 at 23:45
  • 1
    The new example you provided was not a good one, as the only use for the Two-way adapter is to make the Adapter be both the Adaptee and the Target. I'll try to add an example to my answer. – Gabriel Rainha Nov 19 '16 at 00:31
  • I have removed the Adapter method from my updated sample code. Please have a look at it, thank you – Lijin Durairaj Nov 19 '16 at 00:57
  • 1
    I apologise in advance for any coding error on the new sample, as I had to add that from scratch without VS´s glorified help, thus could not test it. I can test it tomorrow if needed, though. – Gabriel Rainha Nov 19 '16 at 01:00