- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这是装饰器模式的有效示例吗?
我想知道此示例是装饰器模式的有效示例吗?如果不是
需要在此处进行更正或更改,请提出建议。
我们有一个Container
类代表容器,为此,我想在
运行。在示例中使用了wheel
和lid
之类的功能。
客户代码:
private void button2_Click(object sender, EventArgs e)
{
IContainer container = new MovableConatiner(new Container());
string features = container.getFeatures();
container = new LidConatiner(container);
features = container.getFeatures();
}
public interface IContainer
{
string getFeatures();
}
public class Container : IContainer
{
public string getFeatures()
{
return "Container";
}
}
// a decorator to add wheels
public class MovableConatiner : IContainer
{
protected IContainer container;
public MovableConatiner(IContainer container)
{
this.container = container;
}
public string getFeatures()
{
string features = container.getFeatures();
features = features != string.Empty ? string.Format("{0} , four wheels", features) :
features;
return features;
}
}
// a decorator to add lid to contaner
public class LidConatiner : IContainer
{
protected IContainer container;
public LidConatiner(IContainer container)
{
this.container = container;
}
public string getFeatures()
{
string features = container.getFeatures();
features = features != string.Empty ? string.Format("{0} , Lid", features) :
features;
return features;
}
}
最佳答案
尽管您的实现不能理想地反映结构或Decorator模式,但从我的角度来看,它解决了Decorator要解决的相同问题。您的解决方案不如"ideal" Decorator implementation那样严格和安全地用于将来的修改。
您简化了实现,为您删除了“不必要的”抽象。但是,尽管您可能认为它们现在不是必需的,但是当您的应用程序扩展并拥有几十个组件和装饰器时,它们在将来会变得非常有用。谁是谁,很容易迷路。
在我提供的链接中,非常简单地描述了Decorator模式的主要参与者,并且有一个示例代码,与您的代码非常相似,但是很完整。我不会在此处复制粘贴它来向您展示正确的实现。
我只想强调一下,如果您不了解设计模式中某些抽象的需求,则最好保留它们,或者再次阅读如何使用它,而不是仅仅删除它们。
更新:赞成抽象:
所有通用逻辑必须在一个地方实现并重用。代码重复非常非常糟糕。我认为每个人都同意这是组织良好的代码的基本原则。
现在,让我们分析装饰器模式的实现,而无需提取装饰器的抽象基类。比较您的MovableContainer
和LidContainer
类的实现-您看到类似的东西吗?实际上,我几乎看不出任何区别。好的,让我们找到常见的地方:
两者都有构造函数,接收要装饰的组件。
两者都存储对装饰的IContainer
的引用
都在getFeatures()方法中检索组件的功能
都检查组件的功能是否为空,如果不是,则附加一些字符串(唯一的区别是字符串本身)
所有这些逻辑都应提取到基类中。您已经应该了解两个装饰器的基类是必需的。
让我们走得更远。让我们想象每个可能的容器的每个可能的装饰器。正如Decorator模式定义所隐含的那样,很明显,所有装饰器都有一些共同的逻辑:它们都存储对装饰对象的引用。是否足以提取基类(单个属性-将其复制粘贴到您拥有的两个装饰器中并不难)?绝对足够!
如果您喜欢真实的例子,就在这里。您实现了很少的装饰器,比方说100(2个仍然是enouth,100只是消除了这个问题)。而且您会意识到有些减速器不知道如何正确使用它们-他们只是将NULL传递给您的装饰器。他们的代码运行良好,然后将创建的装饰器传递到其他地方,或存储到DB等。然后,在某些神奇的地方,您的代码稍后在各个地方失败。很难每次都找到NULL的来源,应用程序的哪个部分创建了这种对象。您决定在构造函数中添加NULL检查,以禁止传递NULL,并使初始代码无法立即解决问题。哎呀,我们需要修复所有100个构造函数!并将您的更改与其他10个开发人员的更改合并,这些开发人员正在每个人的装饰器上工作。那不是一个好的观点。
如果此示例不能使您信服,并且您仍然准备复制粘贴代码100次,请想象您正在开发一个可重用的库,并且其他公司的其他开发人员也实现了从您的IContainer派生的装饰器。您无法修复其装饰器的构造函数,并确保它们不会在内部为您提供无效的对象containsint NULL。相反,如果您有Decorator的基类,则只需要对其进行修复-您和第三方的所有实现都将获得该功能。如果您认为自己没有实现可重用的库,请考虑将其他开发人员作为第3方在团队中工作-它总是很有用,并且没有什么不同-不需要他们更改代码,因为您需要一些修复。
最后,我提供了重构您的代码的方式(我不想在一开始就这样做,而是让您自己来做):
public interface IContainer
{
string getFeatures();
}
public class Container : IContainer
{
public string getFeatures()
{
return "Container";
}
}
public abstract class ContainerDecorator : IContainer
{
protected IContainer container;
protected ContainerDecorator(IContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public abstract string getFeatures();
}
public class StringFormatDecorator : ContainerDecorator
{
private readonly string _format;
public StringFormatDecorator(IContainer container, string format) : base(container)
{
_format = format;
}
public override string getFeatures()
{
string features = container.getFeatures();
features = features != string.Empty ? string.Format(_format, features) : features;
return features;
}
}
// a decorator to add wheels
public class MovableConatiner : StringFormatDecorator
{
public MovableConatiner(IContainer container) : base(container, "{0} , four wheels")
{
}
}
// a decorator to add lid to contaner
public class LidConatiner : StringFormatDecorator
{
public LidConatiner(IContainer container) : base(container, "{0} , Lid")
{
}
}
关于c# - 这是一个有效的Decorator模式示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23733403/
我遇到了一个奇怪的问题。我有这个: $(document).ready(function () {
我正在编写一个程序,它从列表中读取一些 ID,从中找出不同的 URL,然后将图像保存到我的 C: 驱动器中。 如果我在浏览器中导航到图像 URL,它们就会起作用。此外,如果我尝试从不同的服务器获取图像
我编写了一个 REST WCF RIA Silverlight 4.0 兼容服务,我可以从 javascript + jQuery.1.4.2.js + JSON2.js(当然,还可以从 .NET 4
我很确定这个网站实际上还没有得到回答。一劳永逸地,与 32 位有符号整数范围内的数字字符串匹配的最小正则表达式是什么,范围是 -2147483648至 2147483647 . 我必须使用正则表达式进
我有两个data.table;我想从那些与键匹配的元素中随机分配一个元素。我现在这样做的方式相当慢。 让我们具体点;这是一些示例数据: dt1<-data.table(id=sample(letter
我已经安装了 celery 、RabitMQ 和花。我可以浏览到花港。我有以下简单的工作人员,我可以将其附加到 celery 并从 python 程序调用: # -*- coding: utf-8 -
我正在使用 ScalaCheck 在 ScalaTest 中进行一些基于属性的测试。假设我想测试一个函数,f(x: Double): Double仅针对 x >= 0.0 定义的, 并返回 NaN对于
我想检查文件是否具有有效的 IMAGE_DOS_SIGNATURE (MZ) function isMZ(FileName : String) : boolean; var Signature: W
在 Herbert Schildt 的“Java:完整引用,第 9 版”中,有一个让我有点困惑的例子。它的关键点我无法理解可以概括为以下代码: class Test { public stat
我在工作中查看了一些代码,发现了一些我以前没有遇到过的东西: for (; ;) { // Some code here break; } 我们一直调用包含这个的函数,我最近才进去看看它是
在 Herbert Schildt 的“Java:完整引用,第 9 版”中,有一个让我有点困惑的例子。它的关键点我无法理解可以概括为以下代码: class Test { public stat
我试图编写一个函数,获取 2D 点矩阵和概率 p 并以概率 p 更改或交换每个点坐标 所以我问了一个question我试图使用二进制序列作为特定矩阵 swap_matrix=[[0,1],[1,0]]
这个问题在这里已经有了答案: Using / or \\ for folder paths in C# (5 个答案) 关闭 7 年前。 我在某个Class1中有这个功能: public v
PostgreSQL 10.4 我有一张 table : Column | Type ------------------------- id | integer| title
我正在 Postgresql 中编写一个函数,它将返回一些针对特定时区(输入)计算的指标。 示例结果: 主要问题是这只是一个指标。我需要从其他表中获取其他 9 个指标。 对于实现此目标的更简洁的方法有
我需要在 python 中模拟超几何分布(用于不替换采样元素的花哨词)。 设置:有一个装满人口许多弹珠的袋子。弹珠有两种类型,红色和绿色(在以下实现中,弹珠表示为 True 和 False)。从袋子中
我正在使用 MaterializeCSS 框架并动态填充文本输入。我遇到的一个问题是,在我关注该字段之前,valid 和 invalid css 类不会添加到我的字段中。 即使我调用 M.update
是否有重叠 2 个 div 的有效方法。 我有以下内容,但无法让它们重叠。 #top-border{width:100%; height:60px; background:url(image.jpg)
我希望你们中的一位能向我解释为什么编译器要求我在编译单元中重新定义一个静态固定长度数组,尽管我已经在头文件中这样做了。这是一个例子: 我的类.h: #ifndef MYCLASS_H #define
我正在使用旧线程发布试图解决相同问题的新代码。什么是安全 pickle ? this? socks .py from socket import socket from socket import A
我是一名优秀的程序员,十分优秀!