首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >装潢师或门面

装潢师或门面
EN

Software Engineering用户
提问于 2018-11-21 11:44:17
回答 1查看 995关注 0票数 1

如果使用装饰器或外观模式来满足我的需求,我将面临一个问题。

想象一个客户想要播放一段视频。他可以使用这个接口

代码语言:javascript
复制
public interface IVideoPlayer
{
    // Prepares everything to set up and plays the video
    void Play();
}

客户端不应该关注准备工作,因此接口方法的总结说明准备工作是由Play()方法完成的。

准备工作可能包括连接到互联网、登录到服务等不同的内容。对于不同的系统有不同的制备步骤。

外观模式

我可以使用外观模式实现IVideoPlayer,如下所示

代码语言:javascript
复制
VideoPlayerFacade : IVideoPlayer
{
    ctor(...)

    void Play()
    {
        _internetConnection.Connect();
        _loginService.Login();
        _actualVideoPlayer.Play();
    }
}

我不喜欢这种方法:

  • 准备(连接、登录)似乎更像是对实际播放算法的补充,这使我更多地了解了装饰模式。我更愿意理解facade模式来组成一些“相等级别”的步骤来实现一个共同的目标,比如CreateCar()委托给CreateEngine()CreateCarBody()等等。
  • 我面临一个命名问题,因为_actualVideoPlayer实现的接口类型也可以命名为IVideoPlayer,因为它是实际的视频播放器,它也指导我使用装饰器模式。我需要两个几乎相同的接口(一个没有准备,一个没有准备),它们的名字非常相似,我现在无法想象。

解码器模式

可以使用实际的播放算法实现IVideoPlayer,如下所示

代码语言:javascript
复制
VideoPlayer : IVideoPlayer
{
    void Play()
    {
        // do stuff and algorithms
    }
}

准备工作可以由装修人员完成,如下所示

代码语言:javascript
复制
PreparatingVideoPlayer : IVideoPlayer
{
    ctor(...)

    void Play()
    { 
        _internetConnection.Connect();
        _loginService.Login();
        _decoratee.Play();
    }
}

我不喜欢这种方法:

  • 实际上,VideoPlayer违反了Play()方法,因为它不符合接口,没有在D25方法中做好所有准备工作,这反而导致了facade模式。或者它是否违反了LSP,因为当它被注入到系统中时,它总是由PreparatingVideoPlayer来修饰?
  • 如果另一个客户想在没有准备的情况下播放视频(因为客户知道所有事情都是自己准备好或准备好的)怎么办?他不能这样做,因为让IVideoPlayer被注入总是会导致获得PreparatingVideoPlayer,这将使我再次进入外观模式。

结论

那么,哪一种模式更合适,或者这些模式根本不合适?我的担心有效吗?

EN

回答 1

Software Engineering用户

回答已采纳

发布于 2018-11-21 18:53:12

解码器模式

让我们开始吧:我讨厌你的第二个解决方案。

IVideoPlayer是一个接口,是任何实现类都会做某种事情的“契约”。这是一个代码方面的契约(调用者和实现之间的契约),但在某种程度上也是程序员之间的人际关系--如果我用IVideoPlayer擦除硬盘驱动器,编译器就不会阻止我。

<#>The 2实现不是履行相同的契约,它们只是有一个同名的方法。

这里没有给出接口应该提供的安全性。更糟糕的是,由于对这样一份合同的期望,这使得更有可能有人会弄错它。

命名事物

计算机科学中的2件难事,其中之一就是命名东西。不要低估它,词库是最被低估的编程工具之一。您应该有两个不同的名称来表示这两个实现之间的区别。

举个例子,您可以将“外部”一个重命名为VideoSystem:一个是整个系统,另一个只是玩家。或者您可以重命名内部的一个VideoRenderer:一个是整个播放器,而另一个只是部分“渲染”视频。

由于外部API似乎是公开的API,我宁愿重命名内部API,因为您可以更容易地向同事解释内部API,而不是向客户解释外部API。

模式

维基百科提到了装饰模式。

装饰设计模式能解决哪些问题?

  • 应该在运行时动态地将责任添加到(并从)对象中删除。
  • 应该为扩展功能提供一种灵活的子类选择。

关于外观模式,维基百科说

立面设计模式能解决哪些问题?

  • 为了使复杂的子系统更容易使用,应该为子系统中的一组接口提供一个简单的接口。
  • 对子系统的依赖应该最小化。

这两个目标都不是你的目标。

您不需要这样做,因为您希望在运行时动态地添加或删除事物,或者希望扩展功能,或者因为您的子系统太难使用,或者您对子系统有太多的依赖关系。

首先,您正在尝试创建一些功能。

溶液

不要想“我应该采用哪种模式”。做有效的事。最后,您的代码可能是一个已经建立的模式,然后当您的同事询问代码时,您可以告诉他们“我用{模式名称}解决了它”。这就是你从使用模式中获得的所有优势。

所有这些话,做第一件事。

但是,调用facade可能会让人感到困惑,因为很多 人的数量将外观看作是相当简单的类,只是“传递”方法(例如,如果您也有一个调用_internetConnection.Connect();的方法Connect() )。维基百科的例子不这么说,但它们似乎并不特别好(例如,反复使用在构造函数中调用新闻)。

你有一个VideoPlayer类,为了完成它的工作,它需要其他类--我把它叫做好的旧作文。如果你把它叫做作文,没人会误解你的。

票数 5
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/381803

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档