【问题标题】:Create inherited class from base class从基类创建继承类
【发布时间】:2011-02-21 23:25:28
【问题描述】:
public class Car 
{ 
    private string make;
    private string model;
    public Car(string make, string model)
    {
         this.make = make;
         this.model = model;
    }
    public virtual void Display()
    {
       Console.WriteLine("Make: {0}", make);
       Console.WriteLine("Model: {0}", model);
    }
    public string Make
    {
       get{return make;}
       set{make = value;}
    }
    public string Model
    {
       get{return model;}
       set{model = value;}
    }
}

public class SuperCar:Car
{
    private Car car;
    private int horsePower;
    public SuperCar(Car car)
    {
        this.car = car;
    }
    public int HorsePower
    {
       get{return horsePower;}
       set{horsepower = value;}
    }
    public override void Display()
    {
       base.Display();
       Console.WriteLine("I am a super car");
}

当我做类似的事情时

Car myCar = new Car("Porsche", "911");
SuperCar mySupcar = new SuperCar(myCar);
mySupcar.Display();

我只得到“我是一辆超级跑车”,但没有得到我的基类的属性。我应该在 SuperCar 构造函数中明确分配我的基类的属性吗?事实上,我正在尝试装饰器模式,我希望一个类向基类添加行为。

【问题讨论】:

  • 为了让 Supercar 成为真正的装饰者,请将 Car 的所有方法委托给您的包裹汽车。如果 Decorator 是正确的模式,这是值得怀疑的,尤其是当您处理具体的类时。
  • 假设您将 Car 重命名为 Container 并将 SuperCar 重命名为 Box。你说“盒子是一种容器(因为它继承自容器),每个盒子都包含一个容器(因为它在其构造函数中接受一个容器并将其保存在一个字段中)”。这真的是你想要建模的吗?为什么一个盒子应该包含一个容器?为什么 SuperCar 既包含 Car 又是 Car 的一种?

标签: c# design-patterns inheritance decorator


【解决方案1】:

或者:

public class Car
{
    public Car(string make, string model)
    {
         this.make = make;
         this.model = model;
    }


    public Car (Car car):this(car.Make, Car.Model){}
}

public class SuperCar : Car
{
  SuperCar(Car car): base(car){}
}

通过这种方式,您可以从 car 继承任何类,并从提供的对象中填充 car 内容。继承的对象不需要知道要设置什么。他们只是将当前的 Car 对象传递给基类,它就完成了工作。

【讨论】:

    【解决方案2】:

    我可能来晚了一点,但万一有人觉得这很有用:

    您可以使用反射。它需要的代码比您建议的多一点,但我认为它仍然提供您正在搜索的简洁性。

    public SuperCar(Car car)
    {
        var props = typeof(Car).GetProperties().Where(p => !p.GetIndexParameters().Any());
        foreach (var prop in props)
        {
            if (prop.CanWrite)
                prop.SetValue(this, prop.GetValue(car));
        }
    
        // Set SuperCarcentric properties
        // .
        // .
        // .
    }
    

    我从您的示例中明确地写了这个来清楚地说明这个概念,但我认为这最好是一种通用方法,可以在您的解决方案的所有类似实例中使用。

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      查看您的代码,我不确定它是如何编译的。您的构造函数是错误的,因为基本构造函数不知道如何运行采用 car 类型的构造函数。看起来您正在尝试实现装饰器模式,但没有正确完成。真正你应该拥有的是一个ICar 接口,它既可以实现,又可以从SuperCar 中的Display() 调用car.Display() 你还必须在超级汽车上实现Make 和Model 并让它们返回car.Make & car.Model 来正确实现装饰器模式。

      public interface ICar
      {
          string Make {get; set;}
          string Model {get; set;}
          void Display();
      }
      
      public class Car :ICar
      { 
          private string make;
          private string model;
          public Car(string make, string model)
          {
               this.make = make;
               this.model = model;
          }
          public virtual void Display()
          {
             Console.WriteLine("Make: {0}", make);
             Console.WriteLine("Model: {0}", model);
          }
          public string Make
          {
             get{return make;}
             set{make = value;}
          }
          public string Model
          {
             get{return model;}
             set{model = value;}
          }
      }
      
      public class SuperCar:ICar
      {
          private ICar car;
          private int horsePower;
          public SuperCar(ICar car)
          {
              this.car = car;
          }
      
          public string Make
          {
             get{return car.Make;}
             set{car.Make = value;}
          }
          public string Model
          {
             get{return car.Model;}
             set{car.Model = value;}
          }
          public int HorsePower
          {
             get{return horsePower;}
             set{horsepower = value;}
          }
          public override void Display()
          {
             car.Display();
             Console.WriteLine("I am a super car");
      }
      

      【讨论】:

      • 我接受了凯文的回答,因为在我的情况下,我没有接口,我想向现有类添加额外的行为。但是,我感谢您对装饰器模式的完整解释。
      • 是否使用装饰器模式是一个问题。真的,听起来您不想要装饰器模式,因为您只想扩展汽车(这就是继承的用途)而不是包装它并改变它的工作方式,在这种情况下,Kevin's 是正确的解决方案。
      【解决方案4】:

      你没有完全实现decorator pattern

      你需要一个抽象基类来保存装饰好的汽车

        public abstract class CarDecorator
        {
          protected Car DecoratedCar { get; private set; }
      
          protected CarDecorator(Car decoratedCar)
          {
            DecoratedCar = decoratedCar;
          }
        }
      
        public class SuperCar : CarDecorator
        {
          public SuperCar(Car car)
            : base(car)
          {
          }
          public int HorsePower
          {
            get { return horsePower; }
            set { horsepower = value; }
          }
          public override void Display()
          {
            DecoratedCar.Display()
            Console.WriteLine("Plus I'm a super car.");
          }
        }
      

      【讨论】:

      • 但是我可以将 SuperCar 对象分配给 Car 对象,例如将 SuperCar 添加到 List 吗?
      • 不,您需要一份 CarDecorators 列表。
      【解决方案5】:

      将私有属性更改为受保护的属性,除了创建它们的类之外,任何人都无法访问私有属性,而继承的类可以访问受保护的变量。

      【讨论】:

      • 这是否意味着我必须从用于创建 SuperCar 对象的 Car 对象属性中显式分配受保护的变量?
      【解决方案6】:

      是的,要让它按照你的意愿工作,你需要设置基本构造函数,如下所示:

      public SuperCar(Car car):base(car.make,car.model)
      {
        this.car = car;
      }
      

      【讨论】:

        【解决方案7】:

        基于@JoshWheelock 的回答,我编写了这个方法,并将其放入我的 Xamarin 项目的共享文件中

        它克隆类,所以你可以用来复制继承人的基类,你可以调整 T 参数

        //...
        #if WINDOWS_UWP
        using System.Reflection;
        #endif
        //...
        
        public void CloneIn<T>(T src, T dest)
        {
        #if WINDOWS_UWP
            var props = typeof(T).GetTypeInfo().DeclaredProperties.Where(p => !p.GetIndexParameters().Any());
        #else
            var props = typeof(T).GetProperties().Where(p => !p.GetIndexParameters().Any());
        #endif
            foreach (var prop in props)
            {
                if(prop.SetMethod!=null)
                    prop.SetValue(dest, prop.GetValue(src));
            }
        }
        

        尚未在 Android 和 iOS 中进行测试,关于 Android,我的模拟器一周后就彻底停止了正常工作......

        【讨论】:

          猜你喜欢
          • 2011-12-08
          • 1970-01-01
          • 2020-04-20
          • 2016-08-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多