OOP中的对象是否必须代表实体?


82

对象是否必须代表实体?

由一个实体我的意思是这样一个ProductMotor中,ParkingLot等,物理,或甚至一个明确的非物理概念对象-这被很好地定义,其中一些核心数据清楚地属于对象的东西,以及一些功能/方法显然对核心数据起作用。

例如,我可以有一个对象,Demon它本身是一个实体,一个虚构的对象,也许不是物理的,但仍然是一个实体

一个对象可以仅仅是方法的集合,一组与一个共同目标相联系的通用过程吗?

示例:可以在没有实体的情况下调用MotorOperations或的类MotorActions,但是该类内部的方法可以执行以下操作

  • getMotorDataFromHTMLForm()
  • getMotorManufacturers()
  • selectMotorFromUserRequirements($ requirements)
  • canMotorCanHandleOperatingConditions($ conditions)
  • computePowerConsumptionForMotor($ id)

通常将类定义为对象的中心数据+数据操作。因此,Motor对于可能存在一些与电动机规格有关的电动机变量,并且可能存在将这些数据组合以产生某些结果的操作。

就我而言,这更像是我有一个对数据+ 通过该类传递数据的操作的类,除了临时传递类数据之外,没有任何以“ Motor Operations”为中心的数据。

类可以表示无实体的对象吗?如果不是,为什么它们不好/不完整/不以OOP为中心?有什么方法需要在概念上进行更改/改进以符合OOP?


2
+1。但是,“是”是否意味着它必须表示一个实体,还是意味着它们可以表示没有实体的对象?
Panzercrisis

1
我首先想到的是:java.awt及其“ Op”类(例如docs.oracle.com/javase/7/docs/api/java/awt/image/…),如果这就是您的意思。它代表一种操作。现在,我不确定这是否是一个好习惯(看起来确实很怪异和丑陋),但是它包含在Java标准库中,而Java是OOP。在大多数情况下。
路加福音

1
不,不是,但这并不意味着MotorActionsMotorOperations不是好主意。
immibis

1
这个问题可以从对can的进一步说明中受益。
reinierpost

3
@丹尼斯,我真的觉得您在问所有错误的问题。首先,因为没有一个明确的OOP定义,其次,因为范式只是达到目的的一种手段。唯一重要的问题是“以这种方式编写代码是否更容易推断其正确性?” 和“以这种方式编写代码是否更易于重用?”
2015年

Answers:


109

,对象不必代表实体。

实际上,我会辩称,当您停止将对象视为物理实体时,就是您最终获得了OOP所承诺的好处。

这不是最好的例子,但是Coffee Maker的设计可能是开始为我点亮的地方。

对象是关于消息的。他们是关于责任的。它们与汽车,用户或订单无关。

我知道我们以这种方式教OO,但是在尝试了MVC,MVVM或MVWhatever之后,经过几次尝试弄清楚事情的去向是多么令人沮丧,这一点变得显而易见。您的模型变得非常肿,或者控制器变得如此。为了便于导航,很高兴知道所有涉及Vehicles的内容都在Vehicle.ext文件中,但是当您的应用程序涉及Vehicles时,该文件中不可避免地会出现3000行意大利面条。

当您有新消息要发送时,您至少有一个新对象,也许是一对。因此,在您对一堆方法的问题中,我认为您可能正在谈论一堆消息。每个人都可以成为自己的对象,并且要完成自己的工作。没关系。当您将事物分开时,这些事情真的,真的需要在一起,这将变得显而易见。然后你把它们放在一起。但是,为了方便起见,为了方便起见,您不会立即将每种方法都放到一个适当的抽屉中。

让我们谈谈功能包

对象可以只是方法的集合,并且仍然是面向对象的,但是我的 “规则”非常严格。

  1. 馆藏应负有单一责任,并且这种责任不能像“对电动机有影响”那样普遍。我可能会做诸如服务层外观之类的事情,但是我敏锐地意识到,由于导航性/发现性原因,我很懒,而不是因为我试图编写OO代码。

  2. 所有方法都应位于一致的抽象层。如果一种方法检索Motor对象,而另一种方法返回Horsepower,则可能相差太远。

  3. 对象应该处理相同的“种类”的数据。这个对象对电动机起作用(启动/停止),这个对曲柄长度起作用,这个对点火顺序进行处理,这个采取html形式。可以想象,该数据可能是对象上的字段,并且看起来具有凝聚力。

通常,在进行转换,合成或只是不想担心可变性时,我会构建此类对象。

我发现专注于对象责任使我朝着凝聚力迈进。一个对象必须具有一定的凝聚力,但是它不需要任何字段,也不需要太多行为即可成为对象。如果我要构建一个需要这5种电机方法的系统,那么我将以5种不同的对象开始做这些事情。当我发现通用性时,我要么开始将事物合并在一起,要么使用通用的“ helper”对象。这使我陷入了开放/关闭的顾虑-如何提取这一点功能,这样我就不必再次修改该特定文件,而仍在需要的地方使用它?

对象是关于消息的

字段与对象无关紧要-获取和设置寄存器不会改变程序之外的世界。与其他对象协作即可完成工作。但是,OO的优势在于我们可以创建抽象,因此我们不必一次考虑所有单个细节。泄漏或没有意义的抽象是有问题的,因此我们对创建与我们的心理模型匹配的对象进行了深思(也许太多)。

关键问题:为什么这两个对象需要互相交谈?

将对象视为人体中的器官-它具有默认用途,并且仅在收到其关心的特定消息时才更改行为。

设想一下您在人行横道上并且汽车驶速很快的情况。作为大脑的对象,我检测到压力源。我告诉下丘脑发送促肾上腺皮质激素释放激素。垂体得到该信息并释放肾上腺皮质营养激素。肾上腺得到该信息并产生肾上腺素。当肌肉对象收到肾上腺素信息时,它就会收缩。当心脏得到相同的信息时,它会跳动得更快。整个街道上都有众多参与者参与冲刺的复杂行为,而这是重要的信息。大脑对象知道如何使下丘脑发出警报,但它不知道最终会导致行为发生的对象链。同样,心脏也不知道肾上腺素来自何处,

因此,在这个(简化的)示例中,肾上腺对象只需要知道如何服用ACTH并制造肾上腺素。它不需要任何字段来执行此操作,但对我来说仍然像是一个对象。

现在,如果我们的应用程序仅设计用于在街道上冲刺,则可能不需要垂体和肾上腺物体。或者,我只需要一个垂体对象,该对象只占我们在概念上可以称为“垂体模型”的一小部分。这些概念都以概念实体的形式存在,但是它是软件,我们可以制作AdrenalineSender或MuscleContractor或其他任何东西,而不必担心模型的“不完整性”。


4
我同意这个答案的实际内容,但是我觉得它会误解这个问题。具体而言,问题包括在实体“或概念中,定义明确的事物”中。与之相反的例子是“ MotorOperationsMotorActions”。由此,我非常有信心,CoffeeMaker示例中的原始设计最终设计都属于OP的“代表实体”的定义
Ben Aaronson

1
后现代的系统架构DCI无需由热爱结构的工程师创建的极端抽象就可以处理此问题。计算机应该考虑用户的想法,而不是相反。fulloo.info/doku.php?id=what_is_dci
ciscoheat

@BenAaronson我觉得您可以通过协调一致的努力将这个对象发展为具有凝聚力的概念,但是我发现以实体为中心的趋势倾向于将应该分开的事物凝聚在一起。实体鼓励我们使用名字的界限,这是很好的,但它们也带来了正确性/完整性的概念,这往往会造成伤害。用最荒谬的术语来说,我支持FirstNameValidator对象,而反对同时对名字和姓氏进行验证的Name对象。
史蒂夫·杰克逊


2
对象是关于消息的 -史蒂夫·杰克逊的答案-这绝对正确。OO父亲艾伦·凯Alan Kay)的父亲所说的“消息传递”不是MOP的意思,他说,最大的想法是消息传递。而且,很抱歉,我很久以前为该主题创造了“对象”一词,因为它使许多人专注于较小的想法。
radarbob

21

类可以表示无实体的对象吗?如果不是,为什么它们不好/不完整/不以OOP为中心?有什么方法需要更改/改进吗?

简而言之,您可以做任何事情,但是这种特定情况将违反OOP原则:)

您所描述的内容有时称为“实用程序”类-通常是代码气味的标志。您希望避免为了将某些方法保持在一起而创建类。

并非您的应用程序中的每个对象都必须链接到现实生活中的实体,例如电动机或汽车。这些是业务对象。在您的应用程序中,您可能会使用许多业务对象,但对于与业务实体无关的其他操作(如您列出的业务),您还需要更多的隔离。

您应该看一下常见的架构模式-其中之一是MVC(Model-View-Controller)

如果我要分发使用MVC列出的方法,请执行以下操作:

查看类别:

  • GetMotorDataFromHTMLForm()

模型类别(本质上是电机):

  • GetMotorManufacturer()
  • CanMotorHandleOperationConditions()
  • CalculatePowerConsumption()

控制器类(MotorsController):

  • GetAllMotors()
  • GetMotorById()
  • GetMotorByUserRequirements()

似乎您正在使用PHP;Laravel是一个很好的MVC框架。在他们的示例中,他们很好地说明了方法属于什么地方。

另一个更通用的信息源(如何确定方法所属的位置)是GRASPSOLID原理。


谢谢。本质上,在我看来,我所拥有的是一个Controller类,其中混入了一些杂质(例如Model,View等)。这是否意味着,如果我重新命名MotorOperations,以MotorsController和清理了一下,我的收藏功能将与OOP线?
丹尼斯

@Dennis,不一定,请查看我在每个类下收集的方法。Controller不是包含所有内容的类:)它是对模型进行操作的类,仅此而已。控制器的唯一依赖项通常是直接DAL(数据访问层),或者是提供对DAL访问的服务。您从不希望从控制器访问View(例如:getMotorDataFromHTMLForm),相反,您的View应该是依赖于控制器的View。
Alexus 2015年

2
您能否详细说明为什么Utils类会成为代码气味的示例?很好奇,因为我自己喜欢将随机util函数包装在Utils类中,而不是独立的函数……以我的经验,它使代码更具可读性,但是我的经验有限。
HC_ 2015年

3
@HC_具有Utils类与在图片集中拥有“ Misc”文件夹相同。这表明您懒惰地将责任正确地分配给对象/可能丢失的对象,并使用实用程序来弥补。对于Util类,尤其是静态函数,以及对其他类的扩展,还有一定的空间,但是在创建这样的集合之前,请检查是否可以将它们合并到适当的OOP类中:)另一个原因是有时一个类只能具有一种方法。但是,接下来,您需要添加更多内容,并且Utils类变得更加混乱。
Alexus

我经常以Utils库结束,但是我通常尝试以更具描述性的方式对utils类进行分组和命名。如今,有许多开源的“通用实用程序”库已经具有大多数人所需要的通用实用程序,因此在编写自己的实用程序之前,我会先四处看看。
Guy Schalnat

15

类可以表示无实体的对象吗?

能够?是。应该?可能不是-或至少不是您的措辞方式。

实际上,当直接表示物理对象时,对象实际上是最好的,因为现实情况很少将其很好地映射到代码。但是它们确实需要代表一个紧密联系的概念或代码对象。他们需要代表一个整体的责任。

只是将一堆切线相关的函数捆绑在一起是一个名称空间或一个模块-在OOP中不是对象。这些可能有用,但它们并不相同,并且需要不同的使用/思维方式才能有效地工作。


3
bundling a bunch of tangentially related functions together is a namespace:听起来更像是程序范式,而不是面向对象的。
丹尼斯

@dennis-完全(或功能,如果您将其称为模块)。混合范例可能很强大。否则可能会很混乱。
Telastyn

或两者 :) - - - - -
Alexus

@Dennis:或者都不是-仅将与切线相关的功能捆绑在一起在任何范例中都是可疑的做法。
sdenham

我正在处理的代码最初是过程代码库。在某个时候,人们努力将其转换为OOD,但是大多数情况下,都是创建类来“保存函数和方法”,而没有任何实际的OO设计。我已经发现了很多类似的东西,它们试图弥合范例之间的鸿沟,但两者之间却不存在
Dennis

11

一个类应该对某些东西建模-否则就没有意义。但是,建模的内容可能不是物理的“事物”;相反,它可能表示的不是“真实”的东西,而是控制被建模系统所需的东西。例如,在一个交通信号灯控制系统中,您很可能具有某种ControlSignal类,它表示从系统的一部分发送到另一部分的信号,以指示需要执行某些操作。在“现实世界”中,这些信号可能包含电脉冲,这些电脉冲是通过电线从一个盒子传递到另一个盒子的。将不是“真实”的事物建模为具体对象的过程称为“验证”。

祝你好运。


是的,这几乎就是我所说的。类无非是名词的模型。而已。仅此而已。类是一个名词,方法是动词(或消息,如果愿意的话)。一位以这些简单术语思考的初级工程师可以在这些类比分解之前走很长的路(与试图假装类是对物理对象的描述不同-类比几乎在您的第一个项目中开始分解)。
Calphool

7

不。(标题经编辑后提出了相反的问题!)

例如:

Public class MyRepository
{
    public MyObject GetObject(string id)
    {
        //get data from the DB and build an object
    }
}

要么

Public class MyService
{
    public MyObject3 ProcessData(MyObject1 obj1, MyObject2 obj2)
    {
         //perform a process which is not a sole responsiblity of obj1 or obj2
    }
}

但是,通常,OOP背后的理想选择是远离

public struct Car
{
    public Wheel[] Wheels;
}

public int CountWheelsOnCar(MyCarStruct car)
{
   return car.Wheels.Length;
}

public class Car
{
    private Wheel[] wheels;
    Public int CountWheels()
    {
        return this.wheels.Length;
    }
}

您是说它们可以代表无实体的对象吗?(请参阅我在问题上留下的评论。)
Panzercrisis

3
我猜我对OO进行编程的时间太长了-当我看着MyRepository时,我立即在梳妆台上拍了一个玻璃碗,里面放着一堆硬币和废话。达到抢出一分钱,或者一个按钮....
比尔ķ

@pan是一样的服务,在我的例子回购
伊万

@比尔,你这疯狂的老傻瓜!!!多数民众赞成在MyButtonAndOrPennyBowl类!干净的编码ftw
Ewan

1
在我看来,您的第二个示例就像一个打扮成对象的函数,尽管我可能认为还有其他理由(例如,如果函数不是该语言中的一等实体),那么它就没有为自己的理由而被认为是合理的。 )
sdenham 2015年

5

我认为在对类进行编码时,可视化现实世界中的内容会有所帮助,但不是必需的。

实际上,根据您想要的字面意思,我们使用的许多对象根本没有物理表示。例如-考虑MVC体系结构。在现实世界中,即使它们通常由类表示,也没有模型或控制器。这三个通常一起代表某种东西,但并不总是代表某种东西-但正如我说的那样,如果您确实想要(并且可以想象某些东西会有所帮助!我可以某种方式可视化大多数对象-则什么也没有)您将在现实世界中见过)。

通常,您将了解的有关OO的这些“规则”只是一些指导,旨在使您着眼于OO的思考,而不必每天使用它进行编码时就担心很多事情。

顺便说一下,OO本身并不是万灵药,并且在您第一次编写某种解决方案的过程中并没有多大帮助,但是我认为,如果做得对,这是组织代码的绝佳方法,因此它可以提供更多后来很容易理解。编写可维护的代码可能是软件开发中最困难的任务之一,并且在许多情况下(需要不断进行调试/维护的任何情况),到目前为止,这是最重要的。


5

对象是否必须代表实体?

问题:Logger代表哪个实体?

不是隐喻的-从字面上看。

在向学生解释OOP时,以类似于物理世界的方式来解释对象很有帮助。

OOP的父亲之一Alan Kay 写道:

[...]

它的原始概念包括以下部分。

  • 我想到的对象就像生物细胞和/或网络上的单个计算机,只能与消息通信
  • 我想摆脱数据。

[...]

对我而言,面向对象操作仅意味着消息传递,本地保留和保护以及

隐藏状态过程,并限制所有事物的后期绑定。

几乎令人难以置信的硬件架构。我意识到

单元/整个计算机的隐喻将摆脱数据

资源

因此,最好将对象理解为

  • 自给对象封装/隐藏数据

  • 通过消息与其他对象通信

类可以表示无实体的对象吗?

绝对:想想 Math


关于您的示例:

示例:是否可以将一个类称为MotorOperations或MotorActions,其中没有实体,但是该类中的方法会执行类似的操作

  • getMotorDataFromHTMLForm()

  • getMotorManufacturers()

  • selectMotorFromUserRequirements($ requirements)

  • canMotorCanHandleOperatingConditions($ conditions)

  • computePowerConsumptionForMotor($ id)

要确定将这些方法放在哪里,您必须看一下responsibilities谁对什么负责

getMotorDataFromHTMLForm()

这种方法的上下文是构造马达对象。电动机不负责根据通过表单检索的数据来创建自身。至少涉及两个对象;一个是电动机,另一个是电动机创造者

getMotorManufacturers()

编写这种方法的典型上下文是service

selectMotorFromUserRequirements($ requirements)

这也将在service-context中使用

canMotorCanHandleOperatingConditions($ conditions)

这是一个问题motor-object

computePowerConsumptionForMotor($ id)

最好是电动机本身也是一个问题。


tl; dr

形容objects物理对象比提供帮助更具刺激性。


哇,您的答案为OOP注入了生命!我不得不说,我并不是说要以身体为目的。我的问题的意图更多是“一个对象必须是thing具有数据的数据,其中数据显然属于事物,而功能明确地对属于事物的数据进行操作”。因此,在这种情况下,Logger虽然不是物理的东西,但它的概念类似于“物理日志”的概念。是否有数据为核心,以它的状态,而不仅仅是短暂的给它,这可能取决于执行和解释..和更那么,我的问题要去..
丹尼斯

但是是的,答案必须解决我的身体偏见
丹尼斯

3

是的,您可以这样做。但实际上,您是在创建一个类以提供与过程库相同的功能。这样做的唯一原因是您的语言缺少程序模块(例如Java或Ruby)。

在具有过程模块的语言中(我认为PHP具有过程模块),您可能会考虑仅使用过程模块。

您也可以考虑重新设计您的类,以便该类的实例代表一个连贯的对象。

但是,只有在给您额外的功能时才使用OO符号,而不仅仅是为了成为OO!


3

用外行的话

  • 您所描述的称为实用程序类。
  • 它没有状态,这意味着您将永远不需要它的多个实例
  • 所有方法都是静态的,这意味着您必须将所有内容都作为参数传递

确实存在此类,例如Java SDK具有Collections类,该类仅由对集合进行操作或返回集合的静态方法组成。

因此答案是否定的,不是所有类都需要从域实体建模。

另一方面,由于OOP的真正功能在于多态性和封装性,因此在用OOP语言编写的程序中此类类很少或应该很少。

这就像使用飞机从一个地方到另一个地方,不是通过飞行而是通过在高速公路上四处行驶。飞机像汽车一样具有轮子,但它们旨在飞翔。


2

不,类仅表示可以实例化,具有成员并可以继承的东西。

实际上,您的语言可能具有静态类,它们甚至不会被实例化一次以上。

.NET的 Math是“专业”类一个很好的例子,它不代表任何实体(除非您想对什么是数学有所了解...),并且碰巧也说明了此类的合法用例。它只有方法和2个字段(均代表单个常量)。

相似库的类层次结构Math.Net按类型将数学/数值方法分组为类。在这里,类不是代表实体,而是逻辑类别。

我本人通常最终会创建(静态)类,这些类只不过是一袋相关的(静态)函数或一堆方便地集中在一个中央位置的常量。我不会说这是一个好的设计,但是有时候这是最直接的解决方案。


1
将与数学相关的方法作为静态方法放在.NET / BCL中的单独类中的事实不是必需或设计考虑因素,而是C#中没有独立方法的事实的结果。在C ++中,可以将这些函数分组为一个名称空间。
弗拉德

1

您问题的答案最终取决于一个人如何精确定义“阶级”和“实体”等术语。您在定义后者方面做得很好,既允许物理实体也包括概念实体。但是,对纯粹主义者而言,“类”一词将始终是“使用特定内部表示实例化对象的工厂”,对于实用主义者而言,该术语将涵盖那些纯粹主义者所鄙视的Java或C ++事物。实用主义者可能会说Java和C ++会使用“ OOP”一词,但纯正主义者会指阿兰·凯(Alan Kay)指出的意思。考虑到C ++”]]( 那么* Alan Kay到底“面向对象”是什么意思?)。

如果您采取实用主义的观点,则可以接受您的无实例实用程序类。但是,纯粹主义者的观点更有趣。根据Kay的说法,OOP总是比类更多地关注消息。所以对你的问题:

类可以表示无实体的对象吗?

否。类对象进行分类。根据定义,类是您向其发送消息new以产生对象的那些实体。对象是由类制成的实体。存在用于制造对象并确实对其进行分类的类。这就是课程的内容。类制造对象。我们使用类对对象进行分类。因此,如果C 只是一束不允许实例化或子类化的方法,则C 不会有任何对象分类,因此C不是类。

如果不是,为什么它们不好/不完整/不以OOP为中心?

他们还不错。只是不要称他们为课程。一束方法 OOPable的:可以向其发送消息以调用方法的东西,但是它不是类,除非它可以实例化一个对象。你认识露比吗 在Ruby中,模块是一堆方法。甲是可实例化对象的模块。模块没有什么不好的。但是,使类不同于模块(以纯OOP术语而言)的是,类可以具有实例。模块只是一些方法。混淆之处在于C ++和Java及其他语言对类和模块都使用术语“类”

现在,要查看您的特定示例之一,您询问一个MotorOperations可以向其发送computePowerConsumptionForMotor带有arguments 消息的类id。那不好吗?至少它没有违反告诉不提出原则。我们是否必须参加汽车课并向其发送powerConsumption消息?也许不是100%的时间,但是也许尝试做这样的事情将使您对代码有一些深刻的了解。否则,它可能导致小类爆炸,这是不好的。

有什么方法需要在概念上进行更改/改进以符合OOP?

如果“执行OOP”对您很重要,那么您将需要寻找将系统构建为通过相互发送消息进行通信的组件的方法。这是OOP只是什么,或者至少是这个词的coiner心目中。在此视图中,实用程序类不是OOP。但是对某些人来说可能是。

试图从数百万个从类实例化的生活,呼吸,对象中构造出一个大型系统,这可能对某些项目有用。但是,如果您发现自己创建了人为的,听起来有些错误的类,则应该引入模块。尝试强调类,并在可实例化的类很荒谬时使用模块。

TL; DR-方法包并不总是坏的。尝试首先使用可实例化的类。仅在需要时才退回到“模块”。


0

以给定的示例:

getMotorDataFromHTMLForm()
selectMotorFromUserRequirements($requirements)

这些看起来像“工厂”方法,它将返回一个Motor对象。第二个含义是您正在创建一个新的对象以满足要求,或者您正在检查的数据库或内存中的电动机集合。在这种情况下,应该采用这种方法。或者它可以是需求对象上的一种方法。

getMotorManufacturers()

您从哪里得到它们?这就是应该采用的方法。

canMotorCanHandleOperatingConditions($conditions)
computePowerConsumptionForMotor($id)

这些看起来应该是上的方法Motor


是。这是“一堆可能不相关的方法”(简称BOPUM)。我同意工厂和汽车公司的评论。 getMotorManufacturers是从数据库中返回所有电动机制造商。我不确定会去哪里。它会带我一段时间才能解开这个BOPUM放东西的地方,他们需要去..
丹尼斯

getMotorManufacturers从数据库中获取。数据库无法使用方法。目前,我有一个DataMapper模式,该模式可查询数据库,初始化数组并使用Motor Objects(还包含制造商信息)填充该数组,然后将该数组返回给调用方。调用者是我的MotorOperations类,又从一个ProductSelection类中调用(该类包含用于选择Motors的算法,并且加载的Motor信息是该算法的数据)
Dennis

0

对象是具有高度内聚性的方法和数据的集合。它们之所以属于一类,是因为它们之间具有高度的关联性,并且保留了状态。

无论您是使用大型的前期设计并尝试对所有内容建模,还是在新设计中将对象迭代并演化为适合系统需求的新设计,都是如此。

如果没有理由保留状态,则可能没有任何理由实例化对象,这意味着可能没有理由拥有一个类。除非您使用的语言除使用类外,否则无法定义名称空间。使用class应该很好,因为这是习惯用法。

除了典型的方式,我无法想到以这种方式使用类的任何负面方面。您必须实例化“命名空间”,从而引起不必要的成本和复杂性。任何支持此代码的人都会想知道数据在哪里造成了额外的认知负担(很可能是每人一次的花费)。没有任何附加值,这是一种不寻常的用法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.