Oop 我应该把几个(但不是全部)子类所需的变量或方法放在哪里?

Oop 我应该把几个(但不是全部)子类所需的变量或方法放在哪里?,oop,scope,object-oriented-analysis,Oop,Scope,Object Oriented Analysis,从面向对象的最佳实践的角度来看,我应该在父类的某些子类中放置所需的变量或方法,而不是在其他子类中放置所需的变量或方法 前。 类按钮、旋钮、杠杆和开关继承自父类设备。 按钮、操纵杆和开关需要一个布尔值,但旋钮不需要。你会在哪里定义伊森 杠杆和开关需要一个方法Throw()来切换;按钮使用isOn,但不使用Throw()来处理它。这会影响isOn的位置吗?在哪里定义Throw()方法 以上纯粹是一个例子;让我们假设每个子类都有不同的属性来区分它,并且有一些共同点使得使用所讨论的继承模型是合理的。当只

从面向对象的最佳实践的角度来看,我应该在父类的某些子类中放置所需的变量或方法,而不是在其他子类中放置所需的变量或方法

前。 类按钮、旋钮、杠杆和开关继承自父类设备。 按钮、操纵杆和开关需要一个布尔值,但旋钮不需要。你会在哪里定义伊森

杠杆和开关需要一个方法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,因为它是一个可切换控件

谢谢!老实说,自从我上次在教室里讨论起