代码之家  ›  专栏  ›  技术社区  ›  Nick Larsen

有关于这种编程的文献吗?

  •  19
  • Nick Larsen  · 技术社区  · 14 年前

    在大学里,我上了一节现代物理课,在这节课上我们学习了狭义相对论。我完全被不同的参照系是如何实际观察到一个物体的物理性质是不同的,并且两者都不正确所迷惑。随着时间的推移,这个概念慢慢地改变了我的编程方式,现在我倾向于将类分成两个主要类别:数据对象和观察(仅限函数)对象。

    为了避免这个问题变得复杂和冗长,我将通过两个例子来解释我的意思。

    首先,以这种类型的代码为例,我经常写这种代码:

    class Deck
    {
        private Card[] cards;
    
        public void Shuffle()
        {
            // shuffle algorithm
        }
    
        // other deck related functions like draw, cut, etc...
    }
    

    我现在写的场景通常与:

    class Deck
    {
        // by intention, i just mean some kind of immutable collection of cards
        private ReadonlyCollection<Card> _Cards;
    
        public Card[] Cards { get { return this._Cards; } }
    }
    
    interface IDeckHandler
    {
        Deck Shuffle(Deck deck);
        // other deck related functions like draw, cut, etc..
    }
    
    class Dealer : IDeckHandler
    {
        // IDeckHandler implementation
    }
    

    这个 Deck 不再负责实现可以对其执行的功能。或者,为了使其符合术语,数据组只是一组值,观察它的方式是观察者的责任。很自然,会有许多观察者以不同的方式执行这些操作。

    在第二个例子中,我将使用一些我试图解释这一点的人更容易相处的东西。以彩色纸上有彩色字母拼写单词的情况为例。我们有一个代理人,他的责任是读报纸上的字。现在假设代理是某种色盲。从纸上发出的图像是相同的,但感知可能不同。观察者不了解物体,不能对其进行修改,只能对其作出解释。

    正如我所说,这个概念驱动了我的许多开发决策。所以回到问题上来, 这是一种已出版的编程类型吗?如果是,你能给我指一些有关它的文献吗? ?我遇到的一些常见和不常见的情况很难做出决定,当然有些事情我还没有想到或遇到过,希望能在文献中得到检验。

    8 回复  |  直到 6 年前
        1
  •  5
  •   Jordão    14 年前

    您要做的是将概念的数据与作用于该概念的操作分离开来。什么制度 从什么系统 . 这为许多不同的场景打开了大门,在这些场景中,通过使用不同的行为类来更改系统的行为。这些行为类也可以为不同的数据类重用。许多模式都解决了这个问题,比如访问者、命令、策略或观察者。

    但这里有更深层的东西在发挥作用。也许我们需要在我们的(主流)编程语言中使用另一个概念(或者只是在我们的头脑中),这将允许我们分离和重用这些巴哈马。

    这个 DCI architecture 解决这些问题并扮演角色,或 traits (pdf) 作为行为和代码重用的基本单元。

        2
  •  10
  •   Yossale    14 年前

    在我看来,您似乎正在以OOP方式实现函数式编程。 不管对“狭义相对论”的物理解释如何,OOP的整个概念基本上都是封装的——你想让对象知道应该如何做每件事。基本上,您在这里说的是“不,只有数据和函数可以处理数据”。如果甲板变了怎么办?你有新的经销商吗?您如何知道应该创建哪个经销商来处理新平台?

    如果您考虑一个“switch”语句,那么您将把OOP概念锤击到一个函数式编程模板中。

        3
  •  6
  •   Carl Manaster pakore    14 年前

    面向数据编程(一种侧重于数据布局和转换的开发风格)涵盖了这种编程风格的某些方面。

    这种风格的主要问题是,如果给定类型存在隐含的假设/约束(例如,洗牌后纸牌组不能在一行中有两个小丑),则必须在所有管理器类型中重复这些约束/检查,因为您正在操作的数据类型完全是愚蠢的--它不能照顾自己,它只是一个数据包。您可以将重复的逻辑提取到单独的方法中,但使用此方法编写好的、干净的代码通常有点困难。

    将此与实现 Deck.Shuffle 方法 IDeckShuffle 策略。在这个场景中,您可以执行随机播放,然后添加不变量检查作为后期步骤,以确保无论使用什么随机播放策略,数据包都不会进入无效状态;实施完整性的代码位于一个位置,并且易于验证和更新。

    另外,由于对ideckshuffler.shuffle(…)的调用来自数据包内部,因此数据包可以访问所有隐藏字段和封装状态。因此,你可以暴露 最低限度 详细信息到deck shuffler实现,而不是默认通过一个deck。相反,你可以通过 IEnumerable<Card> 或者更不具体的内容,而不是默认地传递整个数据包。

    不管怎样,您所询问的开发形式基本上是程序化编程。因此,隐藏信息和封装东西是很困难的。在性能关键的系统中,这是一个可接受的折衷(按类型对所有数据进行分组,然后使用管理器的“进程”函数对其进行迭代=良好的缓存一致性)。

    在一般的开发中,我远离这种编程风格,因为它严重阻碍了我管理复杂性的能力。 Ayende had a good post about this a while back . 尽管他所说的是一个数据存储对象及其上的操作,但原理是完全相同的——数据的分离、作用于该数据的函数以及其中的问题。

        4
  •  5
  •   jaco0646    6 年前

    这是大多数应用程序的典型布局方式。我认为类是一个二分法——数据容器对象和策略对象。数据容器对象是信息的载体,而策略是可以应用于数据容器的各种算法的封装。

    命令模式非常接近策略模式。策略也倾向于表现为控制器、立面等。

    数据容器对象显示为实体、模型对象、值对象、数据传输对象等。

    “四人帮”是一个很好的开始,但您可能想看看其他经典的设计模式论文,以便进一步阐述。根据您对编程语言的偏好,您可能还需要考虑更具体的模式书。亚马逊有很多关于设计模式的列表。

    我在年谈过班级二分法。 this article .

        5
  •  4
  •   Rui    14 年前

    有趣。嗯,我认为您正在进行模型-控制器-视图(MVC模式),但在这种情况下,您只能分别使用控制器和模型部件。

    如果您有多个使用对象的场景,那么这里的收益是显而易见的,这是一种典型的POJO+管理器方式。在这种情况下,对象本身是哑的,除了它们自己的状态之外,没有任何功能。

    在责任分离的方式上,优势是显而易见的,尽管缺点是在管理者方面处理的事情要多一些。

    如果你想一想,如果对象本身不做任何事情,你基本上就是删掉了一个间接的层次(基础层次),所有的东西都必须是间接的才能使用。这意味着需要更多的代码来处理意外情况、空对象等。可能需要更多的粘合代码。

    灵活的?对。实用?只有你能回答。

        6
  •  4
  •   Dan Bryant    14 年前

    这种设计模式可以很好地工作,特别是在操作不会改变原始数据对象的情况下。例如,在.NET中,可以将Linq及其关联的扩展方法视为处理枚举的常规操作,这样枚举本身就不需要知道如何使用它们。但是,这些方法不会改变正在枚举的集合,而只是提供一种解释、筛选和分组枚举的新方法。

    但是,如果功能正在改变原始对象,那么我倾向于将该功能封装为对象上的方法。这样,对象负责维护其自身的不变量,并且您可以将更多的实现细节与对象的客户机隔离开来。为了使用对象,您必须泄漏的实现细节越多,就越有机会不正确地使用它并导致错误。

        7
  •  1
  •   Michael Wilson    14 年前

    你所说的是一个伟大的“哈哈!”面向对象程序员遇到的时刻。它发生的时候很有趣。我将从“四人帮”的“设计模式”一书开始,然后从那里扩展。

        8
  •  0
  •   Ant Kutschera    13 年前

    在Java世界中,我们有很好的容器,包含无状态会话bean,它可以精确地用于从数据分离行为,由DCI体系结构形式化。这有时被称为面向服务编程。

    OOP通过要求将行为放置在数据所在的类中来约束设计者,以提高一致性,而不是让设计者将相关数据和相关行为放在一起,但不一定也会将行为推送到这些数据类中。

    在一个好的设计中,我们有时在类中有行为,有时在高阶类中有行为。