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)
}