Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 接口与基类_Oop_Interface_Language Agnostic_Base Class_Static Typing - Fatal编程技术网

Oop 接口与基类

Oop 接口与基类,oop,interface,language-agnostic,base-class,static-typing,Oop,Interface,Language Agnostic,Base Class,Static Typing,什么时候应该使用接口,什么时候应该使用基类 如果我不想实际定义方法的基本实现,那么它应该始终是一个接口吗 如果我有一门猫狗课。为什么我要实现IPet而不是PetBase?我能理解ISHED或iBark的接口(IMakesNoise?),因为它们可以逐个宠物放置,但我不知道普通宠物使用哪种接口。现代风格是定义IPet和PetBase 该接口的优点是其他代码可以使用它,而与其他可执行代码没有任何联系。完全“干净”。接口也可以混合 但是基类对于简单实现和公共实用程序很有用。因此,还需要提供一个抽象基类

什么时候应该使用接口,什么时候应该使用基类

如果我不想实际定义方法的基本实现,那么它应该始终是一个接口吗


如果我有一门猫狗课。为什么我要实现IPet而不是PetBase?我能理解ISHED或iBark的接口(IMakesNoise?),因为它们可以逐个宠物放置,但我不知道普通宠物使用哪种接口。

现代风格是定义IPet和PetBase

该接口的优点是其他代码可以使用它,而与其他可执行代码没有任何联系。完全“干净”。接口也可以混合


但是基类对于简单实现和公共实用程序很有用。因此,还需要提供一个抽象基类来节省时间和代码。

现代风格是定义IPet和PetBase

该接口的优点是其他代码可以使用它,而与其他可执行代码没有任何联系。完全“干净”。接口也可以混合


但是基类对于简单实现和公共实用程序很有用。因此,还应提供一个抽象基类以节省时间和代码。

一般来说,您应该更喜欢接口而不是抽象类。使用抽象类的一个原因是,在具体类之间是否有共同的实现。当然,您仍然应该声明一个接口(IPet)并让一个抽象类(PetBase)实现该接口。接口允许最大程度的灵活性和跨边界类型的可移植性。当跨越边界传递引用时,始终传递接口而不是具体类型。这允许接收端确定具体的实现,并提供最大的灵活性。当以TDD/BDD方式编程时,这是绝对正确的


四人帮在他们的书中说“因为继承将子类暴露于其父类实现的细节,所以经常说‘继承破坏了封装’。我相信这是真的。

一般来说,您应该更喜欢接口而不是抽象类。使用抽象类的一个原因是,在具体类之间是否有共同的实现。当然,您仍然应该声明一个接口(IPet)并让一个抽象类(PetBase)实现该接口。接口允许最大程度的灵活性和跨边界类型的可移植性。当跨越边界传递引用时,始终传递接口而不是具体类型。这允许接收端确定具体的实现,并提供最大的灵活性。当以TDD/BDD方式编程时,这是绝对正确的


四人帮在他们的书中说“因为继承将子类暴露于其父类实现的细节,所以经常说‘继承破坏了封装’。我相信这是真的。

一个重要的区别是,您只能继承一个基类,但可以实现许多接口。因此,只有在绝对确定不需要继承其他基类的情况下,才需要使用基类。此外,如果您发现您的接口越来越大,那么您应该开始寻找将其分解为几个定义独立功能的逻辑部分,因为没有规则规定您的类不能全部实现它们(或者您可以定义一个不同的接口,只继承它们来对它们进行分组)一个重要的区别是,您只能继承一个基类,但可以实现许多接口。因此,只有在绝对确定不需要继承其他基类的情况下,才需要使用基类。此外,如果您发现您的接口越来越大,那么您应该开始寻找将其分解为几个定义独立功能的逻辑部分,因为没有规则规定您的类不能全部实现它们(或者您可以定义一个不同的接口,只继承它们来对它们进行分组).

这取决于您的要求。如果IPet足够简单,我更愿意实现它。否则,如果PetBase实现了大量您不想复制的功能,那么请尝试一下

实现基类的缺点是要求
重写现有方法(或
新方法)。这使它们成为虚拟方法,这意味着您必须小心如何使用对象实例


最后,对.NET的单一继承扼杀了我。一个简单的例子:假设您正在创建一个用户控件,那么您继承了
UserControl
。但是,现在您也无法继承
PetBase
。这会迫使您重新组织,例如创建一个
PetBase
类成员。

这取决于您的需求。如果IPet足够简单,我更愿意实现它。否则,如果PetBase实现了大量您不想复制的功能,那么请尝试一下

实现基类的缺点是要求
重写现有方法(或
新方法)。这使它们成为虚拟方法,这意味着您必须小心如何使用对象实例


最后,对.NET的单一继承扼杀了我。一个简单的例子:假设您正在创建一个用户控件,那么您继承了
UserControl
。但是,现在您也无法继承
PetBase
。这会迫使您重新组织,例如创建一个
PetBase
类成员。

在需要之前,我通常不会实现这两个成员。与抽象类相比,我更喜欢接口,因为它提供了更多的灵活性。如果在某些领域有共同的行为
public class Pet
{
    void Bathe();
    void Train(Trick t);
}

public class Dog
{
    private Pet pet;

    public void Bathe() { pet.Bathe(); }
    public void Train(Trick t) { pet.Train(t); }
}

public class Cat
{
    private Pet pet;

    public void Bathe() { pet.Bathe(); }
    public void Train(Trick t) { pet.Train(t); }
}
public abstract class Dog
{
      public virtual void Bark()
      {
        Console.WriteLine("Base Class implementation of Bark");
      }
}

public class GoldenRetriever : Dog
{
   // the Bark method is inherited from the Dog class
}

public class Poodle : Dog
{
  // here we are overriding the base functionality of Bark with our new implementation
  // specific to the Poodle class
  public override void Bark()
  {
     Console.WriteLine("Poodle's implementation of Bark");
  }
}

// Add a list of dogs to a collection and call the bark method.

void Main()
{
    var poodle = new Poodle();
    var goldenRetriever = new GoldenRetriever();

    var dogs = new List<Dog>();
    dogs.Add(poodle);
    dogs.Add(goldenRetriever);

    foreach (var dog in dogs)
    {
       dog.Bark();
    }
}

// Output will be:
// Poodle's implementation of Bark
// Base Class implementation of Bark

// 
// Create ISwimable interface
public interface ISwimable
{
      public void Swim();
}

// Have Human implement ISwimable Interface
public class Human : ISwimable

     public void Swim()
     {
        //Human's implementation of Swim
        Console.WriteLine("I'm a human swimming!");
     }

// Have Duck implement ISwimable interface
public class Duck: ISwimable
{
     public void Swim()
     {
          // Duck's implementation of Swim
          Console.WriteLine("Quack! Quack! I'm a Duck swimming!")
     }
}

//Now they can both be used in places where you just need an object that has the ability "to swim"

public void ShowHowYouSwim(ISwimable somethingThatCanSwim)
{
     somethingThatCanSwim.Swim();
}

public void Main()
{
      var human = new Human();
      var duck = new Duck();

      var listOfThingsThatCanSwim = new List<ISwimable>();

      listOfThingsThatCanSwim.Add(duck);
      listOfThingsThatCanSwim.Add(human);

      foreach (var something in listOfThingsThatCanSwim)
      {
           ShowHowYouSwim(something);
      }
}

 // So at runtime the correct implementation of something.Swim() will be called
 // Output:
 // Quack! Quack! I'm a Duck swimming!
 // I'm a human swimming!
1.  You have a general interface (eg IPet)
2.  You have a implementation that is less general (eg Mammal)
3.  You have many concrete members (eg Cat, Dog, Ape)
public interface IPet{

    public boolean hasHair();

    public boolean walksUprights();

    public boolean hasNipples();
}
public abstract class Mammal() implements IPet{

     @override
     public walksUpright(){
         throw new NotSupportedException("Walks Upright not implemented");
     }

     @override
     public hasNipples(){return true}

     @override
     public hasHair(){return true}
public class Ape extends Mammal(){

    @override
    public walksUpright(return true)
}

public class Catextends Mammal(){

    @override
    public walksUpright(return false)
}