C# 对父类隐藏实现细节
假设我正在设计一个机器人,它可以拾取各种工具并使用它们。 我将创建一个Robot类,它具有拾取方法来拾取我想要使用的工具。 对于每种工具,我都会为其创建一个类,比如说,刀子类,它具有Cut方法。 在机器人上调用拾取方法后,现在我想告诉我的机器人切割。所以对于OOP的概念,我必须告诉机器人,而不是刀子?而Cut方法是在刀子上的,那么我如何调用它呢?我必须在机器人上实现某种C# 对父类隐藏实现细节,c#,oop,C#,Oop,假设我正在设计一个机器人,它可以拾取各种工具并使用它们。 我将创建一个Robot类,它具有拾取方法来拾取我想要使用的工具。 对于每种工具,我都会为其创建一个类,比如说,刀子类,它具有Cut方法。 在机器人上调用拾取方法后,现在我想告诉我的机器人切割。所以对于OOP的概念,我必须告诉机器人,而不是刀子?而Cut方法是在刀子上的,那么我如何调用它呢?我必须在机器人上实现某种useToolCurrentlyHold(),以便将我的命令传播到刀子上。或者我直接使用以下命令调用刀子(我的机器人持有的刀子)
useToolCurrentlyHold()
,以便将我的命令传播到刀子上。或者我直接使用以下命令调用刀子(我的机器人持有的刀子):myrobot.toollcurrentlyinhand.Cut()
我觉得很奇怪,一个父方法必须拥有一切来处理它们所包含的类。现在我有了重复的方法,比如刀子有Cut()
,而现在机器人必须有UseCutOnKnife()
才能在刀子上调用Cut()
,因为良好的OOP实践是将刀子抽象出来,让它感觉像是在订购机器人,而不必担心刀子之类的内部信息
另一个问题是,如果我创作音乐,我会创建音乐
类,其中包含许多度量
类来存储音符信息。在一个度量中,可以有多个Note
类,其中的Note类将包含诸如此Note在度量中的位置或该Note播放的时间等信息。现在我想在尺寸45上加一个注释,放在尺寸的中间。要创建度量值,我必须在音乐上调用CreateMeasure(45)
,然后在度量值上调用CreateNote(0.5f)
?要创建的方法是在父对象上的吗?如果现在我想把音符改为0.25,那么负责改变音符的方法是note
类本身还是measure
类?或者我必须实现在最顶层的音乐类上更改音符的方法
这是我的课程概述:
class Music
{
List<Measure> measures = new List<Measure>();
//methods...
}
class Measure
{
int measureNumber;
List<Note> notes = new List<Note>();
//methods...
}
class Note
{
float positionInMeasure; //from 0 to 1
}
课堂音乐
{
列表度量值=新列表();
//方法。。。
}
阶级尺度
{
内测计数器;
列表注释=新列表();
//方法。。。
}
课堂笔记
{
float positionInMeasure;//从0到1
}
因为现在音乐课是最重要的,我现在必须通过音乐发布所有内容?链接方法以最终调用最里面的类?我认为Action
可能会有所帮助,下面是一些关于它的有用信息,它帮助我理解Action
和Func
,所以一般来说,这是一篇很棒的文章。我建议一种不同的方法。具有刀
和机器人可以拾取的所有其他对象,通过方法使用
(也可以是接口)从通用类项
继承:
现在,实现项的每个类都将有自己的使用方法实现其特定操作
然后,机器人
持有一个通用的项目
,并在不知道它实际是什么的情况下对其调用Use
:
class Robot
{
public Item CurrentItem { get; private set; }
public void PickUpItem(Item i)
{
CurrentItem = i;
}
public void UseItem()
{
CurrentItem.Use(); // will call Use generically on whatever item you're holding
}
}
基本上,我建议您使用拾取(工具工具)
方法创建Robot
类。
Tool
是从中继承具体工具类的接口
看一下Petar Ivanov的回答。他详细解释了我的意思。这里您需要的是一个所有工具都可以实现的通用接口
例如:
现在刀可以实现该接口:
interface Item
{
void Use();
}
class Knife : Item
{
public void Use()
{
// cut action
}
}
class Knife : ITool {
public void Use() {
//do the cutting logic
}
}
现在,您可以通过机器人上的ITool界面使用该工具,但不知道它是什么工具:
class Robot {
private ITool currentTool = null;
public void Pickup(ITool tool)
{
currentTool = tool;
}
public void UseTool() {
currentTool.Use();
}
}
你可以这样调用皮卡:
Robot robot = new Robot();
robot.Pickup(new Knife());
robot.UseTool();
这取决于重点是什么,告诉机器人使用某些东西,或者告诉机器人做某些事情,或者两者兼而有之,如下所示:
public abstract class Task
{
public abstract void Perform(Robot theRobot);
}
public class Cut : Task
{
public string What { get; private set; }
public Cut(string what)
{
What = what;
}
public override void Perform(Robot theRobot)
{
var knife = theRobot.ToolBeingHeld as Knife;
if (knife == null) throw new InvalidOperationException("Must be holding a Knife.");
knife.Use(theRobot);
Console.WriteLine("to cut {0}.", What);
}
}
public class Stab : Task
{
public override void Perform(Robot theRobot)
{
var knife = theRobot.ToolBeingHeld as Knife;
if (knife == null) throw new InvalidOperationException("Must be holding a Knife.");
knife.Use(theRobot);
Console.WriteLine("to stab.");
}
}
public class Bore : Task
{
public override void Perform(Robot theRobot)
{
var drill = theRobot.ToolBeingHeld as Drill;
if (drill == null) throw new InvalidOperationException("Must be holding a Drill.");
drill.Use(theRobot);
Console.WriteLine("to bore a hole.");
}
}
public abstract class Tool
{
public abstract void Use(Robot theRobot);
public abstract void PickUp(Robot theRobot);
public abstract void PutDown(Robot theRobot);
}
public class Knife : Tool
{
public Knife(string kind)
{
Kind = kind;
}
public string Kind { get; private set; }
public override void Use(Robot theRobot)
{
Console.Write("{0} used a {1} knife ", theRobot.Name, Kind);
}
public override void PickUp(Robot theRobot)
{
Console.WriteLine("{0} wielded a {1} knife.", theRobot.Name, Kind);
}
public override void PutDown(Robot theRobot)
{
Console.WriteLine("{0} put down a {1} knife.", theRobot.Name, Kind);
}
}
public class Drill : Tool
{
public override void Use(Robot theRobot)
{
Console.Write("{0} used a drill ", theRobot.Name);
}
public override void PickUp(Robot theRobot)
{
Console.WriteLine("{0} picked up a drill.", theRobot.Name);
}
public override void PutDown(Robot theRobot)
{
Console.WriteLine("{0} put down a drill.", theRobot.Name);
}
}
public class Robot
{
public Robot(string name)
{
Name = name;
}
public string Name { get; private set; }
public Tool ToolBeingHeld { get; private set; }
public void PickUp(Tool tool)
{
if (ToolBeingHeld != null) ToolBeingHeld.PutDown(this);
ToolBeingHeld = tool;
ToolBeingHeld.PickUp(this);
}
public void PutDown()
{
if (ToolBeingHeld != null) ToolBeingHeld.PutDown(this);
ToolBeingHeld = null;
}
public void Perform(Task task)
{
task.Perform(this);
}
}
用法:
var robot = new Robot("Fred the Robot");
robot.PickUp(new Knife("butcher")); // output is "Fred the Robot wielded a butcher knife."
robot.Perform(new Cut("a leg")); // output is "Fred the Robot used a butcher knife to cut a leg."
robot.Perform(new Stab()); // output is "Fred the Robot used a butcher knife to stab."
try { robot.Perform(new Bore()); } // InvalidOperationException: Must be holding a drill.
catch(InvalidOperationException) {}
robot.PutDown(); // output is "Fred the Robot put down a butcher knife."
以机器人为例,在C#中,我将从以下内容开始:
public class Robot
{
private IList<Tool> tools = new List<Tool>();
public void PickUpTool(Tool newTool)
{
// you might check here if he already has the tool being added
tools.Add(newTool);
}
public void DropTool(Tool oldTool)
{
// you should check here if he's holding the tool he's being told to drop
tools.Remove(newTool);
}
public void UseTool(Tool toolToUse)
{
// you might check here if he's holding the tool,
// or automatically add the tool if he's not holding it, etc.
toolToUse.Use();
}
}
public interface Tool
{
void Use();
}
public class Knife : Tool
{
public void Use()
{
// do some cutting
}
}
public class Hammer : Tool
{
public void Use()
{
// do some hammering
}
}
公共类机器人
{
私有IList工具=新列表();
公共无效拾取工具(工具新工具)
{
//你可以在这里检查他是否已经添加了工具
工具。添加(newTool);
}
公共作废工具(工具旧工具)
{
//你应该在这里检查一下他是否拿着别人叫他放下的工具
工具。移除(新工具);
}
公用工具(工具库)
{
//你可以在这里检查一下他是否拿着工具,
//或者如果他没有拿着工具,自动添加工具,等等。
toolToUse.Use();
}
}
公共接口工具
{
无效使用();
}
公共级刀具:工具
{
公共用途()
{
//剪一些
}
}
公共类锤子:工具
{
公共用途()
{
//敲打
}
}
所以机器人只需要知道它有工具,但它不一定在乎告诉他们什么,也不在乎他们如何操作。它只是通过一个标准接口使用它们。这些工具可以包含其他方法和数据,但在本例中它们不包含这些方法和数据。对于问题的机器人部分,每个人都给了你一个很好的答案
至于音乐部分,我不确定我是否会那样做。特别是,我不会将度量值的位置保留在度量值本身中,音符及其位置也是如此。另一件我不太喜欢的事情是,你的位置似乎总是绝对值,这对修改现有音乐没有帮助。也许我在这里遗漏了一些东西,但是当你执行CreateMease(45)并且你的音乐中已经有90个度量值时会发生什么呢?您必须更新以下所有度量值。对于音符位置,我想象你使用float来表示一种“绝对”位置,即何时弹奏音符,而不仅仅是它在另一个音符之后。我想我更喜欢引入一个持续时间属性
var robot = new Robot("Fred the Robot");
robot.PickUp(new Knife("butcher")); // output is "Fred the Robot wielded a butcher knife."
robot.Perform(new Cut("a leg")); // output is "Fred the Robot used a butcher knife to cut a leg."
robot.Perform(new Stab()); // output is "Fred the Robot used a butcher knife to stab."
try { robot.Perform(new Bore()); } // InvalidOperationException: Must be holding a drill.
catch(InvalidOperationException) {}
robot.PutDown(); // output is "Fred the Robot put down a butcher knife."
public class Robot
{
private IList<Tool> tools = new List<Tool>();
public void PickUpTool(Tool newTool)
{
// you might check here if he already has the tool being added
tools.Add(newTool);
}
public void DropTool(Tool oldTool)
{
// you should check here if he's holding the tool he's being told to drop
tools.Remove(newTool);
}
public void UseTool(Tool toolToUse)
{
// you might check here if he's holding the tool,
// or automatically add the tool if he's not holding it, etc.
toolToUse.Use();
}
}
public interface Tool
{
void Use();
}
public class Knife : Tool
{
public void Use()
{
// do some cutting
}
}
public class Hammer : Tool
{
public void Use()
{
// do some hammering
}
}
public class Music
{
public List<Measure> measures = new List<Measure>();
public Measure AddMeasure()
{
Measure newM = new Measure();
measures.Add(newM);
return newM;
}
public Measure CreateMeasure(int pos)
{
Measure newM = new Measure();
measures.Insert(pos, newM);
return newM;
}
public Measure CreateMeasureAfter(Measure aMeasure)
{
Measure newM = new Measure();
int idx = measures.IndexOf(aMeasure);
measures.Insert(idx + 1, newM);
return newM;
}
public Measure CreateMeasureBefore(Measure aMeasure)
{
Measure newM = new Measure();
int idx = measures.IndexOf(aMeasure);
measures.Insert(idx, newM);
return newM;
}
//methods...
}
public class Measure
{
public List<ANote> notes = new List<ANote>();
public void AddANote(ANote aNote)
{
notes.Add(aNote);
}
public void AddANote(int pos, ANote aNote)
{
notes.Insert(pos, aNote);
}
public void AddANoteAfter(ANote aNote, ANote newNote)
{
int idx = notes.IndexOf(aNote);
notes.Insert(idx + 1, newNote);
}
public void AddANoteBefore(ANote aNote, ANote newNote)
{
int idx = notes.IndexOf(aNote);
notes.Insert(idx, newNote);
}
//methods...
}
public abstract class ANote
{
public int duration; // something like 4 for a quarter note/pause and so on
// your stuff
}
public class Note : aNote
{
float frequency; //or whatever else define a note
// your stuff
}
public class Pause: aNote
{
// your stuff
}