- 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/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!