Как работает композиция в C#?

У меня есть класс автомобиля:

public class Car
{    
    private String _Brand;
    private String _Model;
    private Engine _Engine;

    public Car(){

    }

     public String Brand
     {
        get { return _Brand; }
        set { _Brand = value; }
     }

     public String Model
     {
        get { return _Model; }
        set { _Model = value; }
     }

     public Engine Engine
     {
        get { return _Engine; }
        set { _Engine = value; }
     }
}

И класс двигателя:

public class Engine
{
     private int _Code;
     private DateTime _Year;

     public Engine(){

     }

     public int Code
     {
        get { return _Code; }
        set { _Code = value; }
     }

     public DateTime Year
     {
        get { return _Year; }
        set { _Year = value; }
     }
}

Исходя из кода от Registration.aspx.cs, я хочу создать, используя кнопку, Автомобиль и Двигатель с соответствующими отношениями (Композиция).

Тем не менее, у меня возникла путаница в отношении того, как должна вести себя композиция для этих объектов. IE, я не могу понять это, если я должен объявить: Engine = new Engine(); в конструкторе автомобиля или в случае регистрации события (кнопка, код сзади) объявить: Car car = new Car() а потом car.Engine = new Engine();,

Я не понимаю, как работают композиционные отношения в подобном сценарии. Существование того, где декларироватьnew"ставит меня в смешение понятий.

С уважением

4 ответа

Вы можете немного изменить свои классы, как показано ниже, чтобы избежать стандартного кода. Мы просто используем функцию, называемую автоматически реализовать свойства.

public class Engine
{
    public int Code { get; set; }
    public DateTime Year { get; set; }
}

public class Car
{    
    public string Brand { get; set; }
    public string Model { get; set; }
    public Engine Engine {get; set; } 
}

Пожалуйста, обратите внимание, сколько строк кодов было удалено.

Что касается вашего вопроса, вы можете создать объект типа Car используя инициализатор объекта, как показано ниже:

var car = new Car 
{
    Brand = "the brand name";
    Model = "the model name";
    Engine = new Engine
    {
        Code = "the code engine";
        Year = new DateTime(2017,1,1); // the year the engine manufactured.
    }
}

Я бы посоветовал вам прочитать об обеих этих функциях, автоматически реализованных свойствах и инициализаторах объектов. Ниже есть две ссылки на эти функции.

Ну, это зависит от того, как вы хотите контролировать доступность / использование свойства Engine.

Случай 1: если вы хотите, чтобы Car имел полный контроль над свойством Engine, и никто другой не мог получить к нему доступ, сделайте его частным полем и создайте его экземпляр в конструкторе Car.

public class Car
{
    private readonly Engine _engine;
    public Car()
    {
        _engine = new Engine();
    }               
}

Случай 2: Двигатель должен быть доступен снаружи, чтобы любой мог установить его или получить к нему доступ. Это можно сделать двумя способами:

1) Внедрение в конструктор - внедрение зависимости через конструктор, обычно абстрагирующееся с использованием интерфейса, чтобы можно было легко выполнять макетирование / модульное тестирование.

public class Car
{
    public Car(IEngine engine)
    {
        Engine = engine;
    }
    public IEngine Engine { get; set; }
}
var car = new Car(new Engine());

2) Установка свойства Engine вручную

public class Car
 {  
    public Engine Engine { get; set; }           
 }
var car = new Car();
car.Engine = new Engine();

Все зависит от того, как вы разрабатываете свои классы. Автомобиль и двигатель очень общие. Например, если вы хотите создать Mercedes, то имеет смысл создать новый тип MercedesCar, который наследуется от Car. В этом случае вы можете создать экземпляр MercedesEngine из конструктора MercedesCar следующим образом:

public class Car
{
    public Engine Engine
    {
        get;
        private set;
    }

    public Car(Engine engine)
    {
        this.Engine = engine;
    }
}

public class MercedesCar : Car
{
    public MercedesCar() : base(new MercedesEngine())
    {
    }
}

public class Engine
{
}

public class MercedesEngine : Engine
{
}

Но если бы вы придерживались только класса Car, то нет ничего плохого в создании двигателя снаружи!

Я уже несколько лет обсуждаю этот уровень классовой архитектуры, поэтому постараюсь не показаться глупым:)

Начнем с того, что я не думаю, что мы говорим здесь о композиции: (в реальной жизни) жизненный цикл Engine не связан / контролируется Car, Если я правильно понимаю, оба класса пытаются представить карту реальной жизни.

Насколько я знаю, на самом деле, вы можете приобрести Engine к Car, но Car не может функционировать (но может существовать) без Engine (может быть, эти новые фантазии Теслас может?).

Этот крик не является Композицией, поскольку не описывает отношения собственности.

В зависимости от того, насколько строгим вы хотите быть, я бы назвал это Агрегацией (больше) или Ассоциацией (меньше).

Я лично больше склоняюсь к Агрегации, потому что это более сильные отношения, чем, скажем, Car и Spoiler,

Итак, для этого мое предложение будет:

C#

public class Engine
{
     public Engine() { ... }     

     public int Code { get; set; }

     public DateTime Year { get; set; }
}

public class Car
{
     public Car(Engine engine) : this() { 
          this.Engine = engine;
     }

     public Car() {
     } 

     public string Brand { get; set; }

     public String Model { get; set; }

     public Engine Engine { get; set; }
}

Codebehind

var engine = new Engine();
var car = new Car(engine);

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

О композиции

Состав Car быть "целым" и Engine быть "частью" означает, что Engine Жизненный цикл полностью контролируется Car, В этом случае вы в основном заявляете, что "После создания нового объекта Car этот объект внутренне создаст новый Двигатель, который будет утилизирован, когда объект Car больше не используется".

Код для этого будет выглядеть так:

//still the same
public class Engine
{
     public Engine() { ... }     

     public int Code { get; set; }

     public DateTime Year { get; set; }
}

public class Car
{
     public Car() {
        //_engine = new Engine();
     }

     //Engine initialisation can be either here or inside the constructor (check constructor's commented code)
     private readonly Engine _engine = new Engine();

     public string Brand { get; set; }

     public String Model { get; set; }

     //you shouldn't be able to assign an _engine from outside
     public Engine Engine { get { return _engine; } }
}

Композиция Код-позади

var car = new Car();
car.Engine.Code = 123;
Другие вопросы по тегам