I tried to run the following sample program in C# I get the output "You are getting a computer" instead of "You’re getting a computer and a disk and a monitor and a KeyBoard".
Why is this happens C# only not in Java. I java the same code I get the appropriate output.
If I debug I found created object hierarchy is correct but invoking computer.getComputer() always goes to Super class not in drived class, that is the problem.
Please help me to solve this issue.
namespace DecoratorTest1
{
public class Computer
{
public Computer()
{
}
public String getComputer()
{
return "computer";
}
}
public abstract class ComponentDecorator : Computer
{
public abstract String getComputer();
}
public class Disk : ComponentDecorator
{
Computer computer;
public Disk(Computer c)
{
computer = c;
}
public override String getComputer()
{
return computer.getComputer() + " and a disk";
}
}
public class Monitor : ComponentDecorator
{
Computer computer;
public Monitor(Computer c)
{
computer = c;
}
public override String getComputer()
{
return computer.getComputer() + " and a Monitor";
}
}
public class KeyBoard : ComponentDecorator
{
Computer computer;
public KeyBoard(Computer c)
{
computer = c;
}
public override String getComputer()
{
return computer.getComputer() + " and a KeyBoard";
}
public string call()
{
return "";
}
}
class Program
{
static void Main(string[] args)
{
Computer computer = new Computer();
computer = new Disk(computer);
computer = new Monitor(computer);
computer = new KeyBoard(computer);
Console.WriteLine(" You are getting a " + computer.getComputer());
Console.ReadKey();
}
}
}
All functions in C always use the same basic pattern (syntax). This syntax can be captured in a "Design Pattern".
Decorator is a structural pattern that allows adding new behaviors to objects dynamically by placing them inside special wrapper objects, called decorators. Using decorators you can wrap objects countless number of times since both target objects and decorators follow the same interface.
Design Patterns in the object-oriented world is a reusable solution to common software design problems that occur repeatedly in real-world application development. It is a template or description of how to solve problems that can be used in many situations. "A pattern is a recurring solution to a problem in a context."
The Decorator Pattern allows class behavior to the decorated dynamically. It's a structural design pattern as it's used to form large object structures across many disparate objects. The concept of decorator is that it adds additional attributes to an object dynamically.
When using the decorator pattern, the idea is to have several classes implementing the same interface. One of them is the normal concrete implementation of the interface, Computer
in your case. The others add something to the behavior of Computer
. We can get rid of the ComponentDecorator
. You can create an abstract decorator class that implements the IComputer
interface, but you don't have to.
We start by creating the interface and making your concrete Computer
implement it:
public interface IComputer
{
string getComputer();
}
public sealed class Computer : IComputer
{
public string getComputer()
{
return "computer";
}
}
Computer
here is sealed
. It doesn't have to be, but is done in this case to show that decorators exist next to your concrete class, instead of deriving from it.
The 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";
}
}
If you do choose to use an abstract class to implement decorators, have it take an IComputer
as dependency in the constructor. Furthermore, you should then use base.getComputer()
instead of computer.getComputer()
, like so:
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 up in 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 it work with and without abstract decorator.
User InBetween suggested that it might not be possible to change the base class. If the base class already implements an interface, that's not an issue. So let's assume that it doesn't, like in your code.
To implement decorator in this case, we first need to create an adapter for our base class and implement our decorator alongside it.
So let's assume the base class is Computer
and that we can't change it:
public sealed class Computer
{
public string getComputer()
{
return "computer";
}
}
To create an adapter, we create the IComputer
interface like before, and a class that wraps Computer
:
public sealed class ComputerAdapter : IComputer
{
private Computer _computer;
public ComputerAdapter(Computer computer)
{
_computer = computer;
}
public string getComputer()
{
return _computer.getComputer();
}
}
The decorators remain unchanged from the previous example, since they already implement IComputer
. Wrapping it up changes a little, since we now have to pass a 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.
While it doesn't actually implement decorator, your code would work if Computer.getComputer()
was virtual
. In your code, in Main
, computer
is of type Computer
. Since getComputer()
is not virtual
, Computer.getComputer()
is called instead of the intended KeyBoard.getComputer()
. Since in Java every method is always virtual
, that problem doesn't happen.
Your C# compiler should be giving you a warning that getComputer()
from subclasses is hiding the original implementation. Warnings indicate that what you're doing will compile, but might not do what you expect, which is the case here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With