Decorator in C #
When using the decorator template, the idea is to have several classes that implement the same interface. One of them is the usual concrete implementation of the interface, Computer in your case. Others add something to Computer behavior. We can get rid of ComponentDecorator . You can create an abstract decorator class that implements the IComputer interface, but you don't need to.
Beginning of work
Let's start by creating an interface and creating your specific Computer its implementation:
public interface IComputer { string getComputer(); } public sealed class Computer : IComputer { public string getComputer() { return "computer"; } }
Computer here sealed . This is not necessary, but in this case, it is done to show that decorators exist next to your specific class, instead of extracting from it.
No abstract base layer for decorators
Decorators implement IComputer instead of ComponentDecorator :
public class Disk : IComputer { IComputer _computer; public Disk(IComputer computer) { _computer = computer; } public String getComputer() { return _computer.getComputer() + " and a disk"; } } public class Monitor : IComputer { IComputer _computer; public Monitor(IComputer computer) { _computer = computer; } public String getComputer() { return _computer.getComputer() + " and a Monitor"; } } public class KeyBoard : IComputer { IComputer _computer; public KeyBoard(IComputer computer) { _computer = computer; } public String getComputer() { return _computer.getComputer() + " and a KeyBoard"; } }
With an abstract base layer for decorators
If you decide to use an abstract class to implement decorators, keep the IComputer construct in mind as a dependency. In addition, you should use base.getComputer() instead of computer.getComputer() , for example:
public abstract class ComputerDecorator : IComputer { private IComputer _computer; public ComputerDecorator(IComputer computer) { _computer = computer; } public virtual string getComputer() { return _computer.getComputer(); } } public class Disk : ComputerDecorator { public Disk(IComputer computer) : base(computer) { } public override String getComputer() { return base.getComputer() + " and a disk"; } } public class Monitor : ComputerDecorator { public Monitor(IComputer computer) : base(computer) { } public override String getComputer() { return base.getComputer() + " and a Monitor"; } } public class KeyBoard : ComputerDecorator { public KeyBoard(IComputer computer) : base(computer) { } public override String getComputer() { return base.getComputer() + " and a KeyBoard"; } }
In both cases, we can wrap it all the same way:
class Program { public static void Main(string[] args) { IComputer computer = new KeyBoard(new Monitor(new Disk(new Computer()))); Console.WriteLine(" You are getting a " + computer.getComputer()); } }
See how an abstract decorator works with and without .
What if we cannot change the base class
User InBetween suggested that changing the base class is not possible. If the base class already implements the interface, this is not a problem. Therefore, suppose this is not the case as in your code.
To implement a decorator in this case, you first need to create an adapter for our base class and implement our decorator with it.
So, let's say that the base class is Computer and that we cannot change it:
public sealed class Computer { public string getComputer() { return "computer"; } }
To create an adapter, we create the IComputer interface, as before, and the class that wraps Computer :
public sealed class ComputerAdapter : IComputer { private Computer _computer; public ComputerAdapter(Computer computer) { _computer = computer; } public string getComputer() { return _computer.getComputer(); } }
Decorators remain unchanged from the previous example, since they already implement IComputer . Its completion changes a bit, since now we need to pass Computer to our ComputerAdapter instance:
class Program { public static void Main(string[] args) { Computer sealedComputer = new Computer(); IComputer computer = new KeyBoard(new Monitor(new Disk(new ComputerAdapter(sealedComputer)))); Console.WriteLine(" You are getting a " + computer.getComputer()); } }
But the result is the same as can be seen here .
Why is your code working in Java, but not in C #?
Until it implements a decorator, your code will work if computer.getComputer() was virtual . In your code in Main , Computer is of type Computer . Since getComputer() not virtual , KeyBoard.getComputer() is called instead of the expected KeyBoard.getComputer() computer.getComputer() . Since in Java every method is always virtual , this problem does not occur.
Your C # compiler should provide you with a warning that getComputer() from subclasses hides the original implementation. The warnings show that what you do will be compiled, but may not do what you expect to have here.