{"id":10,"date":"2024-08-24T08:44:28","date_gmt":"2024-08-24T08:44:28","guid":{"rendered":"https:\/\/contentlabstudy.com\/soft\/?p=10"},"modified":"2026-09-24T21:15:19","modified_gmt":"2026-09-24T20:15:19","slug":"structural-design-patterns","status":"publish","type":"post","link":"https:\/\/contentlabstudy.com\/soft\/structural-design-patterns\/","title":{"rendered":"Structural Design Patterns"},"content":{"rendered":"<p><strong>Structural design patterns<\/strong> (GoF) compose classes and objects into larger structures without leaking every part\u2019s internals. Use them when the shape of the object graph is the problem \u2014 wrapping, tree-shaped parts, or \u201cmake this look like that.\u201d They are not reliability tactics and not architectural patterns.<\/p>\n<h2>The set that actually shows up<\/h2>\n<ul>\n<li><strong>Adapter<\/strong> \u2014 wrap an existing type so it matches the interface you own. Prefer this over rewriting a third-party SDK. Classic: your <code>IClock<\/code> over <code>DateTime.UtcNow<\/code> in tests.<\/li>\n<li><strong>Decorator<\/strong> \u2014 add behavior by wrapping the same interface (logging, retry, auth). Stack is explicit. Do not subclass just to add a cross-cutting concern.<\/li>\n<li><strong>Facade<\/strong> \u2014 a coarse API over a messy subsystem. Good at a bounded-context edge. Bad if it becomes a god object that knows every table.<\/li>\n<li><strong>Composite<\/strong> \u2014 treat a tree of parts as one part (UI widgets, expression trees, file\/folder). Requires a shared operation that is valid for leaf and node.<\/li>\n<li><strong>Proxy<\/strong> \u2014 stand-in with the same interface (lazy load, remote stub, access check). Virtual proxy vs remote proxy vs protection proxy are different forces; name which one.<\/li>\n<li><strong>Bridge<\/strong> \u2014 split abstraction from implementation so both can vary (shape \u00d7 renderer). Rare; if you only have one implementation, you wanted a strategy or a plain interface.<\/li>\n<li><strong>Flyweight<\/strong> \u2014 share immutable intrinsic state (glyphs, tiles). Profile first; interned strings already do this for you in many runtimes.<\/li>\n<\/ul>\n<h2>Example: decorator, not subclass<\/h2>\n<pre><code>interface IOrders { Order Get(Id id); }\n\nsealed class TracingOrders(IOrders inner, ILogger log) : IOrders\n{\n    public Order Get(Id id)\n    {\n        log.LogInformation(\"get {Id}\", id);\n        return inner.Get(id);\n    }\n}\n<\/code><\/pre>\n<p><code>TracingOrders<\/code> is still an <code>IOrders<\/code>. Tests can skip it. A subclass of <code>SqlOrders<\/code> would couple tracing to SQL.<\/p>\n<h2>What breaks it<\/h2>\n<p>A subclass that logs from inside <code>SqlOrders<\/code> couples tracing to SQL. The decorator above implements the same interface, so a test can skip it.<\/p>\n<pre><code>class SqlOrders : IOrders\n{\n    public virtual Order Get(Id id) =&gt; new(id);\n}\n\nclass TracingSqlOrders : SqlOrders\n{\n    public override Order Get(Id id)\n    {\n        \/\/ The log call is stuck to the SQL class. A test of Get now needs the logger.\n        return base.Get(id);\n    }\n}<\/code><\/pre>\n<h2>Do not confuse<\/h2>\n<ul>\n<li><strong>Adapter vs facade<\/strong> \u2014 adapter matches an interface you already have; facade invents a simpler one.<\/li>\n<li><strong>Decorator vs proxy<\/strong> \u2014 decorator adds responsibility; proxy controls access or lifetime. Same wrapping shape, different intent.<\/li>\n<li><strong>Composite vs inheritance trees<\/strong> \u2014 composite is a runtime tree of parts, not a class hierarchy of \u201cis-a\u201d.<\/li>\n<\/ul>\n<p>If the problem is \u201cthis call might fail\u201d or \u201cthis message is huge,\u201d you want <a href=\"\/soft\/reliability-design-patterns\/\">reliability<\/a> or <a href=\"\/soft\/message-brokers-and-large-messages\/\">messaging<\/a> patterns, not GoF structural ones.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Structural design patterns (GoF) compose classes and objects into larger structures without leaking every part\u2019s internals. Use them when the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-10","post","type-post","status-publish","format-standard","hentry","category-software-design"],"_links":{"self":[{"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/posts\/10","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/comments?post=10"}],"version-history":[{"count":5,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/posts\/10\/revisions"}],"predecessor-version":[{"id":3221,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/posts\/10\/revisions\/3221"}],"wp:attachment":[{"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/media?parent=10"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/categories?post=10"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/tags?post=10"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}