Oop 我应该把几个(但不是全部)子类所需的变量或方法放在哪里?
从面向对象的最佳实践的角度来看,我应该在父类的某些子类中放置所需的变量或方法,而不是在其他子类中放置所需的变量或方法 前。 类按钮、旋钮、杠杆和开关继承自父类设备。 按钮、操纵杆和开关需要一个布尔值,但旋钮不需要。你会在哪里定义伊森 杠杆和开关需要一个方法Throw()来切换;按钮使用isOn,但不使用Throw()来处理它。这会影响isOn的位置吗?在哪里定义Throw()方法Oop 我应该把几个(但不是全部)子类所需的变量或方法放在哪里?,oop,scope,object-oriented-analysis,Oop,Scope,Object Oriented Analysis,从面向对象的最佳实践的角度来看,我应该在父类的某些子类中放置所需的变量或方法,而不是在其他子类中放置所需的变量或方法 前。 类按钮、旋钮、杠杆和开关继承自父类设备。 按钮、操纵杆和开关需要一个布尔值,但旋钮不需要。你会在哪里定义伊森 杠杆和开关需要一个方法Throw()来切换;按钮使用isOn,但不使用Throw()来处理它。这会影响isOn的位置吗?在哪里定义Throw()方法 以上纯粹是一个例子;让我们假设每个子类都有不同的属性来区分它,并且有一些共同点使得使用所讨论的继承模型是合理的。当只
以上纯粹是一个例子;让我们假设每个子类都有不同的属性来区分它,并且有一些共同点使得使用所讨论的继承模型是合理的。当只有子类的子集共享功能时,这可以用包含所讨论的方法的接口来表示,它只由需要它们的子类实现
public interface OnOffable {
boolean isOn();
void toggleOnOff();
void turnOn(boolean is_on);
void turnOn();
void turnOff();
}
class Switch extends Device implements OnOffable...
如果一个或多个函数相当复杂,则可以创建一个静态实用程序函数来帮助防止冗余代码。然而,在本例中,“复杂”是保持开关状态的需要
在这种情况下,您可以创建一个OnOffableComposer
,它(我的首选项)不实现OnOffableComposer
实际上,由于这个特定的接口可以完全实现(意味着它不需要受保护或抽象的函数),它实际上可以是它的“简单”实现:
public class SimpleOnOffable implements OnOffable {
private boolean isOn;
public class OnOffableComposer(boolean is_on) {
turnOn(is_on);
}
public boolean isOn() {
return isOn;
}
public void turnOn(boolean is_on) {
isOn = is_on;
}
public void toggleOnOff() {
turnOn(!isOn());
}
public void turnOn() {
turnOn(true);
}
public void turnOff() {
turnOn(false);
}
}
下面是它的使用方法:
public class Switch extends Device implements OnOffable {
private final SimpleOnOffable smplOnOff;
public Switch(boolean is_on) {
smplOnOff = new SimpleOnOffable(is_on);
}
public boolean isOn() {
return smplOnOff.isOn();
}
public void turnOn(boolean is_on) {
smplOnOff.turnOn(is_on);
}
public void toggleOnOff() {
smplOnOff.toggleOnOff();
}
public void turnOn() {
smplOnOff.turnOn();
}
public void turnOff() {
smplOnOff.turnOff();
}
}
尽管这位作曲家很“简单”,但这一切都表明了音乐的概念。它允许比单一继承更复杂的设计。这听起来像是错误的抽象。至少,
旋钮
不属于其他旋钮。我可能会在设备
和三个密切相关的设备之间插入一个类。可能类似于BinaryDevice
:
abstract class Device {}
abstract class BinaryDevice : Device {
abstract void Activate();
abstract void Deactivate();
}
class Switch : BinaryDevice {
void Activate() { // activate the switch }
void Deactivate() { // deactivate the switch }
}
// same for Lever, which honestly is really just a Switch with a different styling and may not even need to be a separate object
class Button : BinaryDevice {
void Activate() { // activate the button, then immediately call Deactivate() }
void Deactivate() { // deactivate the button }
}
旋钮
也可以从设备
继承,但在这一点上,设备
没有通用功能,因此不清楚为什么需要通用的通用基类。随着进一步的功能被添加到各种设备中,可能确实存在向上推到基类的公共功能。事实上,像这样的重构模式已经很成熟了
对于上面的类,我认为在错误状态下调用操作时会出现错误处理。例如,很难想象一个场景,一个按钮
需要任何人对其调用Deactivate()
,因为它会自动取消激活。(尽管就像现实生活中的按钮可能会卡住一样,如果它调用的操作因某种原因挂起,这个按钮也可能会卡住。)但无论如何,即使是其他对象上的Activate()
和Deactivate()
也需要检查状态。例如,无法激活已激活的开关
关键是,当更加仔细地考虑术语和真实世界建模时,对象模型的清晰性开始变得更加明显。很多时候,开发人员试图将术语硬塞进一些常用术语中,以最大限度地利用继承之类的东西,不幸的是,这常常导致错误的抽象和混乱的领域模型
按照对象自然存在的方式构建对象,然后寻找可以抽象为通用功能的模式。不要试图先定义公共功能,然后强制对象适应该模型。一般来说,我会说,如果在一些但不是所有子类中需要父类的元素,那么应该引入中间父类 定义继承层次结构时,合乎逻辑的假设是父级的子级应该共享该共同祖先的所有属性。这类似于a的工作方式,有助于保持代码的整洁 因此,让我们看看系统中的对象(我们将使用“is a”关系来帮助我们了解继承层次结构): 按钮、旋钮、杠杆和开关 这些设备中的每一个都可能被称为“设备”,但当我们说“设备”时,大多数人可能会想到手机或平板电脑等数字设备。描述这些对象的更好的词可能是“控件”,因为这些对象帮助您控制事物 所有对象都是控件吗?确实是,因此每个对象都将在其继承层次结构中将控件作为父对象 我们需要进一步分类吗?您的要求是具有开/关状态,但并非每个控件都具有开/关状态,而只是其中的一部分。让我们进一步将它们分为控制和切换控制 每个控件都是切换控件吗?不,所以这些是独立的对象类。 每个切换控件都是控件吗?是的,所以ToggleControl可以从控件继承。 所有对象是否正确分类,所有子对象是否共享所有父属性?是的,我们已经完成了继承层次结构的构建 因此,我们的继承层次结构如下所示:
Control (Code shared by all controls)
/ \
/ \
Knob ToggleControl (Code shared by all controls that can also be toggled - Adds isOn)
\
\
Button, Lever, Switch
现在,到你问题的另一部分:
杠杆和开关需要一个方法Throw()来切换;按钮使用isOn,但不使用Throw()来处理它。这会影响isOn的位置吗?在哪里定义Throw()方法
首先,“throw”是一个保留字(至少在Java中是这样),所以使用类似于保留字的方法名可能会引起混淆。该方法最好命名为“toggle()”
按钮应该(事实上它必须)使用toggle()来切换它的isOn,因为它是一个可切换控件 谢谢!老实说,自从我上次在教室里讨论起