第一次海报刚刚学习c#。我过去几天一直在玩弄问题,失败,谷歌搜索,重试,学习。但现在想要吸引任何可以帮助提供一点指导的人。基本思想是与接口一起使用。
只是为了说明目的而写这篇文章......假设我有动物园展览。展览包含动物。我想把每只动物放在笼子里,把动物放在笼子里的功能对于所有动物都是一样的。为此,我将为所有动物定义一个通用接口IAnimal。
public class ZooExhibit {
public List<IAnimal> animalList;
public ZooExhibit(){
animalList = new List<IAnimal> ();
}
public void AddAnimal(IAnimal animal){
animalList.Add (animal);
}
public void CageAnimals(){
foreach (IAnimal a in animalList){
a.PutInCage();
}
}
}
IAnimal看起来像:
public interface IAnimal {
int CageNumber { get; set; }
void PutInCage ();
}
如果我想要猴子展览,我可以写一些类似的东西:
public class Zoo {
public ZooExhibit monkeyExhibit;
public CreateExhibit(){
monkeyExhibit = new ZooExhibit();
monkeyExhibit.AddAnimal(new Monkey());
monkeyExhibit.AddAnimal(new Monkey());
monkeyExhibit.AddAnimal(new Monkey());
monkeyExhibit.CageAnimal();
}
}
因此PutInCage()代码获取IAnimal的对象并将其放入笼中。 PutInCage()还记录每只动物所在的CageNumber,并且是可以通过IAnimal接口访问的属性。
现在这是我的问题。每只动物都有不同的特性。他们都有CageNumber,但猴子可能拥有财产&#34; Height&#34;和大象可能有&#34;重量&#34;一只老虎可能有&#34;颜色&#34;。所以我们可以把动物放在笼子里,但由于它们在IAnimal界面,我们只能获得Cage数字,尽管我可能有兴趣根据笼子里的动物获取和设置不同的属性。
有没有人对总体方向有任何建议?我完全误解了在哪里使用接口?我只需要为每只动物制作一个功能吗?另外,是否有一个关键字我应该考虑更多地解决这个问题?
感谢。我很欣赏这个指导。
答案 0 :(得分:1)
你的困惑源于坏的例子。从技术上讲,你知道界面是什么以及如何实现它,但你做了一个例子,它无法帮助你理解界面如何有用。
在示例中,普通继承更合适,具有可空笼数的动物。如果它被分配,动物就被关在笼子里。
如果展览不仅展出动物,还展示汽车和绘画,你会使用界面。然后你会有不同的类型,有不同的祖先。那些不适合单个继承树。然而,您需要共同的行为或属性(通常只是行为)。这就是接口进入的地方以及有用的地方。
Cagability完全与动物有关,因此拥有一个接口是没有意义的,可以在Animal基类中很好地实现可陷性。但现在考虑出售物品,您为获取展品而支付的款项或者您要向人们收取费用的钱。那些会调用接口IDisplayItem或IExhibitItem。
界面允许您超级键入不同的类。在这种情况下,动物,汽车和绘画。
答案 1 :(得分:0)
你走在正确的轨道上。
应该分离出笼子的概念
class Cage
{
public int Number { get; set; }
public List<IAnimal> Animals { get; set;} = new List<IAnimal>();
public Cage Lockup(IAnimal animal) { Animals.Add(animal); return this;}
}
那么你可以选择像
这样的东西public class Zoo
{
List<Cage> Cages = new List<Cage>()
public Cage AddCage(int number)
{
var cage = new Cage(){Number = number}
Cages.Add(cage);
return cage;
}
}
Zoo.AddCage(1).Lockup(new Sheep()).Lockup(new Lion()).CageFight();
但是现在你需要考虑如何一般地处理具有不同属性的动物。
一个选择是你对这些属性有一个通用的概念,你可能会去IAnimal.Stats,它返回关于每只动物的统计数据列表。
另一种选择是每只动物都知道如何展示自己。
另一种选择是使用访客模式之类的东西来恢复特定类型,以便为每只动物做特定的事情
答案 2 :(得分:0)
如果您真的希望这是可重复使用和更通用的行为,您需要识别“常见”行为, 抽象。所以,基于你的帖子:“我想把每只动物放在笼子里,功能把动物放在笼子里对所有动物都是一样的。”这是你试图抽象的行为。你想要像ICageable这样的东西。您希望具体类和依赖类相互依赖于抽象。
如果你认为A类取决于B类,那么它更可重复使用并解耦为A类依赖于接口C而B类则依赖于接口C。
如果这没有意义,请告诉我,我可以提供更具体的代码示例。基本上,你通常都是在ISomethingable之后。
我建议您阅读开放/封闭原则和一般的SOLID原则。
答案 3 :(得分:0)
我认为您需要了解is and as operators。
基本上,你可以迭代你的动物集合,如果你需要获得一些特定的属性,你可以使用这些运算符来相应地转换和处理目标对象。
IEnumerable<IAnimal> animalList = new List<IAnimal>();
foreach (IAnimal a in animalList)
{
a.PutInCage();
//if it's a monkey get its height
if (a is Monkey)
{
var monkey = (Monkey)a; //cast is safe here because you ensure it's a money in the if statement.
Show(monkey.Height);
}
else
{
//try to get it as an elephant
var elephant = a as Elephant;
if (elephant != null)
Show(elephant.Weight);
}
}
如您所见,您可以使用is
来避免通过首先询问目标对象是否为给定类型来获取空引用异常。另一方面,您使用as
来尝试强制转换操作,但如果对象不是给定类型,您将获得一个null对象,因此您必须检查null。
希望这有帮助!
答案 4 :(得分:0)
听起来你需要泛型。
试试这个:
public class ZooExhibit<A> where A : IAnimal
{
public List<A> animalList;
public ZooExhibit()
{
animalList = new List<A>();
}
public void AddAnimal(A animal)
{
animalList.Add(animal);
}
public void CageAnimals()
{
foreach (A a in animalList)
{
a.PutInCage();
}
}
}
然后你可以这样做:
public class Zoo
{
public ZooExhibit<Monkey> monkeyExhibit;
public void CreateExhibit()
{
monkeyExhibit = new ZooExhibit<Monkey>();
monkeyExhibit.AddAnimal(new Monkey());
monkeyExhibit.AddAnimal(new Monkey());
monkeyExhibit.AddAnimal(new Monkey());
monkeyExhibit.CageAnimals();
}
}
现在monkeyExhibit.animalList
将是Monkey
的强类型列表。