Phần sau kết hợp một số khía cạnh tốt nhất của một số câu trả lời khác cũng như một kỹ thuật để cho phép khía cạnh quan trọng của Cat
việc có Excrement
thuộc tính thuộc RadioactivePoo
loại bắt buộc , nhưng có thể trả lại điều đó như Poo
thể chúng ta chỉ biết rằng chúng ta có một thuộc tính AnimalBase
hơn là cụ thể a Cat
.
Người gọi không bắt buộc phải sử dụng các hàm chung, ngay cả khi chúng có mặt trong các triển khai, cũng như không gọi một hàm có tên khác để trở nên đặc biệt Poo
.
Lớp trung gian AnimalWithSpecialisations
chỉ phục vụ để niêm phong thuộc Excrement
tính, kết nối nó qua thuộc tính không công khai SpecialPoo
với lớp dẫn xuất AnimalWithSpecialPoo<TPoo>
có Excrement
thuộc tính kiểu trả về dẫn xuất.
Nếu Cat
là động vật duy nhất Poo
đặc biệt theo bất kỳ cách nào hoặc chúng tôi không muốn loại động vật Excrement
trở thành đặc điểm xác định chính của a Cat
, thì lớp chung chung trung gian có thể bị bỏ qua trong hệ thống phân cấp, để dẫn Cat
xuất trực tiếp từ AnimalWithSpecialisations
, nhưng nếu có là một số loài động vật khác nhau có đặc điểm cơ bản là chúng Poo
đặc biệt theo một cách nào đó, việc tách "boilerplate" thành các lớp trung gian giúp giữ cho Cat
bản thân lớp khá sạch sẽ, mặc dù phải trả thêm một vài lệnh gọi hàm ảo.
Mã ví dụ cho thấy rằng hầu hết các hoạt động mong đợi đều hoạt động "như mong đợi".
public interface IExcretePoo<out TPoo>
where TPoo : Poo
{
TPoo Excrement { get; }
}
public class Poo
{ }
public class RadioactivePoo : Poo
{ }
public class AnimalBase : IExcretePoo<Poo>
{
public virtual Poo Excrement { get { return new Poo(); } }
}
public class Dog : AnimalBase
{
}
public abstract class AnimalWithSpecialisations : AnimalBase
{
public sealed override Poo Excrement { get { return SpecialPoo; } }
protected virtual Poo SpecialPoo { get { return base.Excrement; } }
}
public abstract class AnimalWithSpecialPoo<TPoo> : AnimalWithSpecialisations, IExcretePoo<TPoo>
where TPoo : Poo
{
sealed protected override Poo SpecialPoo { get { return Excrement; } }
public new abstract TPoo Excrement { get; }
}
public class Cat : AnimalWithSpecialPoo<RadioactivePoo>
{
public override RadioactivePoo Excrement { get { return new RadioactivePoo(); } }
}
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog();
Poo dogPoo = dog.Excrement;
Cat cat = new Cat();
RadioactivePoo catPoo = cat.Excrement;
AnimalBase animal = cat;
Poo animalPoo = catPoo;
animalPoo = animal.Excrement;
AnimalWithSpecialPoo<RadioactivePoo> radioactivePooingAnimal = cat;
RadioactivePoo radioactivePoo = radioactivePooingAnimal.Excrement;
IExcretePoo<Poo> pooExcreter = cat;
IExcretePoo<RadioactivePoo> radioactivePooExcreter = cat;
animal = dog;
animalPoo = dogPoo;
pooExcreter = dog;
}