/
Decorator.razor
183 lines (149 loc) · 11.3 KB
/
Decorator.razor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
@page "/blogs/structural-design-pattern-decorator"
@using DesignPatternDemoComponents.Decorator
@inherits FragmentNavigationBase
@inject TableOfContents tableOfContents
<Content Description=@Description
Slug=@Slug
PosterPath=@PosterPath
Channel="@Channel"
ContentType="@ContentType"
TotalContents=@TotalContents
Type="DesignPattern"
FileName=@nameof(Decorator)>
<ContentBody>
<p>
In this article, let's learn about <ContentHighlight>Decorator Design Pattern</ContentHighlight> in .NET.
</p>
<h3 class="[ font-semibold text-lg ]">Table of Contents</h3>
<ol class="[ list-decimal ] [ ml-4 ]">
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#introduction")" Match="NavLinkMatch.All">
Introduction
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#structure")" Match="NavLinkMatch.All">
Structure
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#use-cases")" Match="NavLinkMatch.All">
Use Cases
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#advantages")" Match="NavLinkMatch.All">
Advantages
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#disadvantages")" Match="NavLinkMatch.All">
Disadvantages
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#related-patterns")" Match="NavLinkMatch.All">
Related Patterns
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#summary")" Match="NavLinkMatch.All">
Summary
</NavLink>
</li>
</ol>
<h3 id="introduction" class="[ font-semibold text-lg ]">Introduction</h3>
<p>
The <ContentHighlight>decorator</ContentHighlight> pattern is a design pattern that allow <ContentHighlight>dynamically attach additional
responsibilities to an object</ContentHighlight>, providing a <ContentHighlight>flexible alternative to subclassing</ContentHighlight> for
extending functionality. Also referred to as a <ContentHighlight>wrapper</ContentHighlight>, the decorator pattern allows for the
<ContentHighlight>dynamic addition of responsibilities to an object at runtime</ContentHighlight>.
</p>
<p>
By using the decorator pattern, we can <ContentHighlight>avoid violating Single Responsibility Principle</ContentHighlight>. Our classes would get
littered with code that doesn't necessarily belong there. That's where the decorator pattern comes in.
</p>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<h3 id="structure" class="[ font-semibold text-lg ]">Structure</h3>
<dl>
<dt><ContentHighlight>Component (IRepository):</ContentHighlight></dt>
<dd>Defines the <ContentHighlight>interface</ContentHighlight> for objects that can have responsibilities added to them.</dd>
<dt><ContentHighlight>Concrete Component (DatabaseRepository):</ContentHighlight></dt>
<dd>Defines the <ContentHighlight>logic</ContentHighlight> to read data from database.</dd>
<dt><ContentHighlight>Decorator (RepositoryDecoratorBase):</ContentHighlight></dt>
<dd>
An <ContentHighlight>abstract class</ContentHighlight> implementing the same <ContentHighlight>interface</ContentHighlight> as the
<ContentHighlight>component</ContentHighlight> and maintains a reference to a <ContentHighlight>component object</ContentHighlight>. It
defines an <ContentHighlight>interface</ContentHighlight> that conforms to the component's <ContentHighlight>interface</ContentHighlight>.
</dd>
<dt><ContentHighlight>Concrete Decorator (CachedRepositoryDecorator):</ContentHighlight></dt>
<dd>Implements the decorator <ContentHighlight>abstract class</ContentHighlight> and adds specific behavior or state to the component.</dd>
</dl>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<GithubGistSnippet Title="Code Sample - Decorator Pattern" UserId="fingers10" FileName="6454ba113536c4b3a57261a4fd47b0ed"></GithubGistSnippet>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<p>
In the above code, we're implementing the <ContentHighlight>decorator</ContentHighlight> pattern for a <ContentHighlight>repository</ContentHighlight>
system. The <ContentHighlight>IRepository interface</ContentHighlight> defines the base functionality with a <ContentHighlight>ReadData</ContentHighlight>
method. The <ContentHighlight>DatabaseRepository class</ContentHighlight> is a <ContentHighlight>concrete component</ContentHighlight> that retrieves data
from a database. The <ContentHighlight>RepositoryDecoratorBase abstract class</ContentHighlight> acts as the <ContentHighlight>decorator base</ContentHighlight>,
maintaining a reference to a repository and <ContentHighlight>delegating</ContentHighlight> the <ContentHighlight>ReadData</ContentHighlight> method. Finally,
the <ContentHighlight>CachedDatabaseRepository class</ContentHighlight> is a <ContentHighlight>concrete decorator</ContentHighlight> that extends the behavior
by adding caching logic. If a random probability is less than 20%, it returns cached data; otherwise, it delegates to the base repository's
<ContentHighlight>ReadData</ContentHighlight> method. This <ContentHighlight>structure</ContentHighlight> allows <ContentHighlight>dynamic</ContentHighlight>
composition of repository behaviors, adding features like caching without modifying the core repository code.
</p>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<DemoSnippet Title="Decorator Pattern Demo">
<p>
Let's try <ContentHighlight>Decorator</ContentHighlight> Demo, Click on the <ContentHighlight>Read via Decorator</ContentHighlight> Button to
see the demo on the screen. Click the button multiple times to see the data being read from cache or from database based on cache availability.
For demo purpose, radomness is introduced to simulate the cache availability. In reality, it could be based on time.
</p>
<GithubGistSnippet Title="Decorator Pattern Demo" UserId="fingers10" FileName="25d0f573f3f61ab5f41b703fff54001f"></GithubGistSnippet>
<DecoratorDemo></DecoratorDemo>
</DemoSnippet>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<h3 id="use-cases" class="[ font-semibold text-lg ]">Use Cases</h3>
<ul class="[ list-disc ] [ ml-4 ]">
<li><ContentHighlight>Dynamic Responsibility Addition</ContentHighlight> - When there's a need to add responsibilities to individual objects dynamically at runtime without affecting other objects.</li>
<li><ContentHighlight>Dynamic Responsibility Removal</ContentHighlight> - When the added responsibilities need to be withdrawn dynamically.</li>
<li><ContentHighlight>Extension by Subclass is Impractical</ContentHighlight> - When extending functionality through subclassing results in an impractical or impossible solution.</li>
</ul>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<h3 id="advantages" class="[ font-semibold text-lg ]">Advantages</h3>
<ul class="[ list-disc ] [ ml-4 ]">
<li><ContentHighlight>Flexibility</ContentHighlight> - Dynamically add or remove responsibilities at runtime.</li>
<li><ContentHighlight>Single Responsibility Principle</ContentHighlight> - Helps adhere to the single responsibility principle by separating concerns.</li>
</ul>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<h3 id="disadvantages" class="[ font-semibold text-lg ]">Disadvantages</h3>
<p>
<ContentHighlight>System Litter</ContentHighlight> - This pattern may result in a system with many small, simple classes, potentially increasing the effort required for learning and debugging. Despite
these points, the Decorator pattern is a useful starting point because of its simplicity. Finally, let's have a look at related patterns.
</p>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<h3 id="related-patterns" class="[ font-semibold text-lg ]">Related Patterns</h3>
<ul class="[ list-disc ] [ ml-4 ]">
<li><ContentHighlight>adapter</ContentHighlight> pattern</li>
<li><ContentHighlight>composite</ContentHighlight> pattern</li>
<li><ContentHighlight>strategy</ContentHighlight> pattern</li>
</ul>
<GoogleAdSense Type="GoogleAdSenseAdType.InArticle" Format="GoogleAdSenseAdFormat.Fluid" Style="text-align:center;" Slot="3914293965"></GoogleAdSense>
<h3 id="summary" class="[ font-semibold text-lg ]">Summary</h3>
<p>
In this article we learn't about the <ContentHighlight>decorator</ContentHighlight> pattern that provides a <ContentHighlight>flexible</ContentHighlight>
way to <ContentHighlight>extend the functionality of objects dynamically at runtime</ContentHighlight>. It promotes flexibility and adherence to the
<ContentHighlight>single responsibility principle</ContentHighlight>, although it may lead to a system with <ContentHighlight>many small classes</ContentHighlight>.
Understanding its structure and use cases enables developers to leverage its benefits effectively.
</p>
</ContentBody>
</Content>
@code {
private string Description = "In this post I will teach you Structural Decorator Design Pattern in .NET. All with live working demo.";
private string Slug = "structural-design-pattern-decorator";
private string PosterPath = "Blogs/Design-Pattern";
private string Channel = "design-pattern";
private string ContentType = "blogs";
private ushort TotalContents => (ushort)tableOfContents.Contents.Count(content => content.Type.Equals("Design-Pattern", StringComparison.CurrentCultureIgnoreCase));
}