1

我有两个继承自同一个抽象类的类。我希望他们两个或至少一个知道另一个特定属性的变化。有什么简单的方法可以做到这一点吗?我一直在尝试将变量移动到父类,但这只会创建 2 个相同的变量,并且当我在第一个类中创建对另一个类的引用时,也会发生同样的事情。谢谢。

这就是我的代码的样子:

public abstract class Animal
    {
        public int MovementSpeed;
        public bool Death;
        public string Feedback;

        public bool DeerCaught;
        public int tiredRate;
        public virtual int Movement()
        {
            MovementSpeed = MovementSpeed - tiredRate;
            return MovementSpeed;
        }

        public virtual string Print()
        {
            return Feedback;
        }
    }

    public class Deer : Animal
    {
        public string hidden;
        public string Foraging;

        public int DeerCount;


        public Deer()
        {
            this.DeerCount = 10;
            this.DeerCaught = false;
            this.MovementSpeed = 10;
            this.tiredRate = 2;

        }
        public void Hide()
        {
            if (Hunting)
            {
                Feedback = "The deer is hiding.";
                if (DeerCount > 0)
                {
                    Print(); 
                }

            }
            else
            {
                //Forage();
            }
        }
        public void Forage()
        {
            if (!Hunting)
            {
                Feedback = "The deer is searching for food.";
                if (DeerCount > 0)
                {
                    Print();
                }

            }
            else
            {
                //Hide();
            }
        }
    }

    public class Wolf : Animal
    {

        public int Hunger;
        public bool Hunting;
        public Wolf()
        {
            this.Hunting = false;
            this.Hunger = 10;
            this.MovementSpeed = 10;
            this.tiredRate = 1;
        }
        public bool Hunt()
        {
            if (Hunger < 5)
            {
                Hunting = true;
                Feedback = "The wolf is searching for his next meal.";
                if (DeerCaught == true)
                {
                    Hunger++;
                }
                else
                {
                    Hunger--;
                }
                return Hunting;
            }
            else
            {
                Hunting = false;
                Feedback = "The wolf decides to rest.";
                Hunger--;
                return Hunting;
            }
        }
        public void Die()
        {
            if (Hunger < 0)
            {
                Death = true;
                Feedback = "The wolf has lost the hunt.";
            }

        }

    }

我已经尝试Hunting在基类中设置为静态,但是当我运行每个类的方法时,我最终得到了两个不同版本的“Hunting”。

4

5 回答 5

5

如果这是为了模拟,那么当狼在打猎时,鹿不会被告知,它必须找出答案。这里的类比是让鹿可以通过某种方式查询狼的存在(类似于Deer.LookForWolves(),然后检查Hunting每只狼的属性值。这将需要某种控制器类,代表世界。

class World
{
    public static List<Animal> Animals = new List<Animal>();
    //...
}

class Deer : Animal
{
    //...

    bool IsSafe()
    {
        return LookForWolves().All(wolf => !wolf.Hunting);
    }

    List<Wolf> LookForWolves()
    {
        return World.Animals.OfType<Wolf>();
    }

    //...

或者,您可以World作为 each 的成员引用Animal,通过构造函数传入。这取决于您,并且取决于您是否需要拥有多个World对象,每个对象都有不同的Animals 列表。

于 2013-03-01T11:11:24.603 回答
2

诸如实施之类的东西INotifyPropertyChanged可能会有所帮助:

首先,声明一些实现的类INotifyPropertyChanged

abstract class Base {

}

class ClassA : Base, INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    private string _property;
    public string ClassAProperty {
        get {
            return _property;
        }
        set {
            _property = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ClassAProperty"));
        }
    }
}

class ClassB : Base, INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;

    private string _property;
    public string ClassBProperty {
        get {
            return _property;
        }
        set {
            _property = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ClassBProperty"));
        }
    }
}

然后,连接新实例以订阅该PropertyChanged事件:

using System.ComponentModel;

static void Main(string[] args) {
    ClassA a = new ClassA();
    a.PropertyChanged += PropertyChanged;
    a.ClassAProperty = "Default value";

    ClassB b = new ClassB();
    b.PropertyChanged += PropertyChanged;
    b.ClassBProperty = "Default value";

    b.ClassBProperty = "new value in B";
    a.ClassAProperty = "new value in A";

    Console.Read();
}

static void PropertyChanged(object sender, PropertyChangedEventArgs e) {
    Console.WriteLine("Property {0} on object {1} was changed, the value is \"{2}\"", e.PropertyName, sender.GetType().Name, sender.GetType().GetProperty(e.PropertyName).GetValue(sender));
}

这个的输出是:

Property ClassAProperty on object ClassA was changed, the value is "Default value"
Property ClassBProperty on object ClassB was changed, the value is "Default value"
Property ClassBProperty on object ClassB was changed, the value is "new value in B"
Property ClassAProperty on object ClassA was changed, the value is "new value in A"

每次设置任一属性时,PropertyChanged都会调用它,在上面的示例中,它将详细信息写入控制台。

在您的用例中,您将让事件调用另一个类中的方法(如果我理解正确的话)。

于 2013-03-01T10:42:29.790 回答
1

一种非常基本的方式来通知您自己的委托定义更改的属性。由于您不提供任何代码,因此我自己编写了一些类。以此为例来修改您自己的代码:

public delegate void PropertyChangedEventHandler();

public abstract class Base
{
}

public class A : Base
{
    public event PropertyChangedEventHandler PropertyChanged;

    private int _value;
    public int Value
    {
        get { return _value; }
        set 
        { 
            _value = value;
            if (PropertyChanged != null)
            {
                PropertyChanged();
        }
    }
}

public class B : Base
{
    private A _a;

    public B(A a)
    {
        _a = a;
        a.PropertyChanged += new PropertyChangedEventHandler(a_PropertyChanged);
    }

    private void  a_PropertyChanged()
    {
        Console.WriteLine(_a.Value);
    }
}

public class Application()
{
    public void DoStuff()
    {
        var a = new A();
        var b = new B(a);
    }
}
于 2013-03-01T10:47:29.953 回答
1

基本思想是将一个对象的引用传递给另一个对象。例如告诉鹿它正在被狼猎杀:

public class Wolf : Animal
{
    public void Hunt(Deer deer)
    {
        deer.SetHunter(this);
    }
}

现在鹿可以检查是否有狼在猎杀它:

public class Deer : Animal
{
    Wolf _hunter;
    public void SetHunter(Wolf wolf)
    {
        _hunter = wolf;
    }

    public void Hide()
    {
        if (_hunter != null)
        {
            Feedback = "The deer is hiding.";
        }
        else
        {
            //Forage();
        }
    }
}

这可以改进为更通用,但这是将一个对象的引用传递给另一个对象的基本思想。

于 2013-03-01T11:29:57.870 回答
1

不要将公共字段用于类的属性。这样您将永远不会知道更改,因此无法通知其他人。将公共字段放入属性中,并始终使用这些属性来更改值,即使是在 Animal 类内部也是如此。然后可以使用属性设置器将更改通知其他人。

public abstract class Animal
{
    private int _movementSpeed;

    public int MovementSpeed
    {
        get
        {
            return _movementSpeed;
        }
        set
        {
            if (_movementSpeed != value)
            {
                _movementSpeed = value;
                OnMovementSpeedChanged();
            }
        }
    }

    protected virtual void OnMovementSpeedChanged()
    {
        // Derived classes can override this method.
        // It will be called each time MovementSpeed changes.
    }

    public virtual int Movement()
    {
        // always use the property to change the value
        // otherwise OnMovementSpeedChanged would never be called
        MovementSpeed -= tiredRate;
        return MovementSpeed;
    }
}

像已经提到的其他人一样,您也可以INotifyPropertyChanged在您的基类中实现。由于这使用事件进行通知,因此不仅派生类可以使用它,而且任何其他引用动物的对象也可以使用。方法基本相同。每次属性值更改时,您都会调用一个触发事件的方法。然后任何其他对象都可以处理该事件。

public abstract class Animal : INotifyPropertyChanged
{
    private int _movementSpeed;

    public int MovementSpeed
    {
        get
        {
            return _movementSpeed;
        }
        set
        {
            if (_movementSpeed != value)
            {
                _movementSpeed = value;

                // call this method each time a property changes
                OnPropertyChanged(new PropertyChangedEventArgs("MovementSpeed"));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        // always implement events like this
        // -> check if the event handler is not null, then fire it
        if (PropertyChanged != null)
        {
            PropertyChanged(this, args);
        }
    }
}

想要处理事件的类可以这样做:

public class AnyClass
{
    public AnyClass(Animal anAnimal)
    {
        TheAnimal = anAnimal;
        anAnimal += Animal_PropertyChanged;
    }

    public Animal TheAnimal { get; private set; }

    private void Animal_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "MovementSpeed")
        {
            Console.WriteLine("MovementSpeed changed"); 
        }
    }
}

然而,派生类不需要处理事件。由于 OnPropertyChanged 方法被声明为受保护的虚拟方法,因此它们可以直接覆盖它。

public class Deer : Animal
{
    protected override void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "MovementSpeed")
        {
            Console.WriteLine("MovementSpeed changed");
        }

        // don't forget to call the base class otherwise the event will never get fired
        base.OnPropertyChanged(args);
    }
}
于 2013-03-01T11:35:34.463 回答