Применение в другом классе переменной в C#

У меня есть класс простой Player:

// Класс игрока
public class Player
{
    private string _name;
}

Также, например, хочу сделать класс Enemy, в котором хочу применить переменную _name(Только в этом классе). Вопрос, мне надо в классе Enemy наследоваться от Player или есть другое решение?

Дополнение: Например, у нас есть класс "монетка" и когда игрок подбирает монетку, то в классе "монетка" вызывается метод, который выводит следующее - "Игрок {_name (Из класса Player) подобрал монетку}". Как это реализовать максимально правивльно?


Ответы (3 шт):

Автор решения: Sterlukin

Не совсем понятны конкретные мотивы этого. Если поле _name должно быть во всех классах-сущностях, описывающих персонажей, то есть смысл определить вот таких образом:

public class Player
{
     protected string Name { get; set; }
}

public class Enemy : Player
{
     //здесь будет доступно поле Name
}

Если вы имели в виду что-то другое, то сформулируйте задачу чуть более конкретно в комментарии.

→ Ссылка
Автор решения: Alex Krass

Проектирование классов ООП строится на простых логических цепочках.

Спросите себя, может ли враг Enemy быть прямым наследником игрока Player? Игрок Player в теории должен управлять игроком, взаимодействовать с другими игроками, быть хорошим и иметь другие характеристики. Класс Enemy как по мне всем этим не обладает, к тому же изменения Player могут отразиться на Enemy, поэтому тут ошибка логического проектирования.

После лирического отступления, напрямую к способам.

Можно просто задублировать, ведь логически это разные сущности.

В этом в принципе нет ничего плохого, ведь лучше задублировать сейчас, чем в будущем при переписывании страдать от собственного наследования и разделять эти сущности.

public class Player
{
    private string _name;
}

public class Enemy
{
    private string _name;
}

Можно выделить общего родителя, чтобы сохранить логику.

Однако учтите, что наследоваться можно только от одного класса. Обратите внимания на измененный модификатор доступа на protected.

public class Character
{
    protected string _name;
}

public class Player : Character
{
}

public class Enemy : Character
{
}

Можно избавляться от зависимостей с помощью интерфейсов.

В основном это нужно для того, чтобы обработка в методах шла одинаковым образом.

public interface ICharacter
{
    string name { get; set; }
}

public class Player : ICharacter
{
    public string name { get; set; }
}

public class Enemy : ICharacter
{
    public string name { get; set; }
}

Тогда можно обрабатывать сущности так:

List<ICharacter> list = new List<ICharacter>()
{
    new Player(), new Enemy()
}
foreach(ICharacter character in list)
    Console.WriteLine(character.name);

Есть еще всякие паттерны проектирования, но это уже другая история.

public class Player
{
    public string name { get; set; }
}

public class Enemy 
{
    private Player player;
    public string name { get; set; }

    public Enemy(Player player) { this.player = player; }

    public void Attack()
    {
        Console.WriteLine($"Враг {this.name} была атакован игроком {player.name}");
    }
}

P.S. Судя по описанию, общий родительский класс вполне подойдет.

→ Ссылка
Автор решения: Yaroslav
public abstract class Unit {

    public string Name { get; protected set; } // Можно запросить, но нельзя изменить из вне Unit и его наследников
    protected UnitControl control; // Доступно только для Unit и его наследников
    // Дольнейшие общие переменные

    public abstract void Dead (); // Функция не реализована, но обязательна для реализации у наследников
    // Дольнейший общий функционал
}

public class Player : Unit {

    public Player () {
        Name = "Hero";
        control = new PlayerControl();
    }

    public override void Dead () {
        // GameOver
    }
}

public class Enemy : Unit {

    public Enemy () {
        Name = "Monster";
        control = new EnemyControl();
    }

    public override void Dead () {
        // Drop Loot
    }
}

public class Test {
    
    public Test () {
        Enemy NewEnemy = enw Enemy();
        Console.WriteLine(NewEnemy.Name); // можно
        NewEnemy.Name = "Gollum"; // нельзя
    }
}

Name публичная переменная. get позволяет обратиться к ней кому угодно, а protected set позволит задавать это поле только самому Unit и тем, кто от него наследуется, защищая от внешнего редактирования.

Если Enemy, родственный классу Player, то не Enemy наследуется от Player, а они оба наследуются от некого общего Unit. abstract значит, что Unit не может быть создан сам по себе (new Unit()), он как болванка описывающая функции.

А вообще вам бы почитать про наследование. Узнаете много интересного, чем будете пользоваться всегда и везде.

→ Ссылка