С# тестовое задание
Подскажите пожалуйста новичку. Есть тестовое задание по C#:
Case A job of 1000 images is going to be edited by a crew of 3 people:
- P1: 1 image per 2 minutes
- P2: 1 image per 3 minutes
- P3: 1 image per 4 minutes How long will this job take in total?
How many images will be edited by every person?Scoring:
- Correct answer and explain the necessary steps
- Working code
- It should work for any situation (amount of images, amount of people, individual speed)
Please focus on:
- OOP implementation;
- N-tier architecture implementation;
- Unit testing implementation;
- General programming rules and standards usage.
Есть код :
Подскажите что нужно еще сделать для того, чтобы проект был готовым для собеседования. Как сделать юнит тестирование?
public class Image
{
public int Id { get; }
public string Title { get; }
public Image(int id, string title)
{
Id = id;
Title = title;
}
}
using System;
using System.Collections.Generic;
/// <summary>Рабочий.</summary>
public class Worker
{
/// <summary>Имя рабочего.</summary>
public string Name { get; }
/// <summary>Возвращает изображение монтируемое рабочим.
/// Если <see langword="null"/>, то значит рабочий простаивает. </summary>
public Image CurrentImage { get; private set; }
/// <summary>Делегат метода для получения рабочим изображения для обработки.</summary>
private readonly Func<Image> getCurrentImage;
/// <summary>Время необходимое рабочему для обработки изображения.</summary>
public int ProcessTime { get; }
/// <summary>Время затраченное рабочим на обработку текущего изображения.</summary>
public int ProcessingTime { get; private set; }
// Мутабельный список изображений, уже обработанных рабочим.
private readonly List<Image> processedIages = new List<Image>();
/// <summary>Иммутабельный список изображений, уже обработанных рабочим.</summary>
public IReadOnlyList<Image> ProcessedIages;
public Worker(string name, Func<Image> getCurrentImage, int processTime)
{
Name = name;
this.getCurrentImage = getCurrentImage;
ProcessTime = processTime;
ProcessedIages = processedIages.AsReadOnly();
}
/// <summary>Количество интервалов в которые рабочий работал.</summary>
public int CountWorkingInterval { get; private set; }
/// <summary>Метод выполнения следующего интервала.</summary>
public void NextWorkingInterval()
{
if (CurrentImage != null)
{
ProcessingTime--;
CountWorkingInterval++;
}
if (ProcessingTime == 0)
{
if (CurrentImage != null)
processedIages.Add(CurrentImage);
CurrentImage = getCurrentImage();
if (CurrentImage != null)
ProcessingTime = ProcessTime;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
public class Brigade
{
private readonly Queue<Image> images = new Queue<Image>();
private readonly List<Worker> workers = new List<Worker>();
private Image GetNextImage()
{
if (images.Count == 0)
return null;
return images.Dequeue();
}
public Brigade()
{
for (int i = 0; i < 1000; i++)
{
images.Enqueue(new Image(i, $"Изображение №{i + 1}"));
}
workers.Add(new Worker("Первый", GetNextImage, 2));
workers.Add(new Worker("Второй", GetNextImage, 3));
workers.Add(new Worker("Третий", GetNextImage, 4));
}
public bool NextWorkingInterval()
{
workers.ForEach(w => w.NextWorkingInterval());
return images.Count != 0 || workers.Any(w => w.CurrentImage != null);
}
public void WorkStart()
{
while (NextWorkingInterval())
{
Console.WriteLine($"Картин в очереди: {images.Count}");
}
foreach (var worker in workers)
{
Console.WriteLine($"{worker.Name}: {worker.CountWorkingInterval} - {worker.ProcessedIages.Count}");
}
}
}
static void Main(string[] args)
{
Brigade brigade = new Brigade();
brigade.WorkStart();
}
код на C++. помогите переписать на C#
#include <iostream>
#include<stdio.h>
#include<cmath>
using namespace std;
class IMG_Edit{
public:
IMG_Edit()
{
int img=1000;
int time=0;
int group_quantity=3;
Person = new double[group_quantity];
for (int i=0;i<group_quantity;i++)
{
Person[i]=i+2;
}
};
IMG_Edit(int img,int group){
this -> img=img;
time=0;
group_quantity=group;
Person=new double[group_quantity];
for (int i=0;i<group_quantity;i++)
{
Person[i]=i+2;
}
};
void set_speed(int p_num,int speed){
Person[p_num-1]=speed;
}
void set_img(int i)
{
img=i;
};
void set_group(int group){
group_quantity=group;
delete[]Person;
Person=new double [group_quantity];
for(int i=0;i<group_quantity;i++){
Person[i]=i+2;
}
};
void show_info()
{
double temp_img=img;
double img_per_min=0;
for(int i=0;i<group_quantity;i++){
img_per_min+=(1/Person[i]);
}
while(temp_img>=0)
{
temp_img=img_per_min;
time++;
}
};
double temp;
if (time>60)
{
cout<<"this job will take in total:"<<time/60<<"hours"<<time%60<<"minutes"<<endl;
}
else{
cout<<"this job will take in total:"<<time<<"minutes"<<endl;
}
for (int i=0;i<group_quantity;i++)
{
cout<<"Person"<<i+1<<"edited:"<<temp<<"images"<<endl;
}
time=0;
cout<<endl;
};
~ IMG_Edit(){
delete []Person;
}
private:
double img;
double*Person;
int group_quantity;
int time;
};
void Menu()
{
cout<<"choose option"<<endl;
cout<<"1. Calculate & display the result"<<endl;
cout<<"2. set images quantity"<<endl;
cout<<"3. set amount of people in the group"<<endl;
cout<<"4. set individual speed"<<endl;
cout<<"0. Quit"<<endl;
};
int main()
{
int answer=0;
system("cls");
IMG_Edit obj;
cout<<"\n result of the task"<<endl;
cout<<"Conditions: 100 images, 3 persons, default speed"<<endl;
obj.show_info();
cout<<endl;
cout<<"choose option"<<endl;
cout<<"1. change conditions"<<endl;
cout<<"2. explanation to the answer"<<endl;
cout<<"0. Quit"<<endl;
cin>>answer;
while(answer<0||answer>2)
{
cout<<"you entered an invalid value! try again..."<<endl;
cin>>answer;
}
if (answer==2)
{
system("cls");
cout<<"\n 2. explanation to the answer"<<endl;
cout<<"first the number of processed images in 1 minute"<<endl;
cout<<"s=1/p(s-speed of one person in one minute, p - speed of editing one picture by one person)"<<endl;
cout<<"then summarize the value of the speed of all people in one minute"<<endl;
cout<<"Next, create a cycle, the condition of wich is the presence of unprocessed images"<<endl;
cout<<"each iterations of the cycle, substract from the number of unprocessed images the value"<<endl;
cout<<"of the number of edited images in one minute by all people and increase the value of time by one minute"<<endl;
cout<<"after the end of cycle, show the time in a readable form(hh,mm)"<<endl;
cout<<"\n and display the number of edited images by each person"<<endl;
cout<<"change conditions"<<endl;
cout<<"0. Quit"<<endl;
cin>>answer;
}
if(answer==1)
{
int img, group, speed, person;
system("cls");
cout<<"\n 2. input conditions"<<endl;
cout<<"amount of images - \b\b"<<endl;
cin>>img;
cout<<"amount of people - \b\b"<<endl;
cin>>group;
IMG_Edit obj(img,group);
do
{system("cls");
Menu();
cin>>answer;
while(answer<0||answer>4)
{
cout<<"you entered an invalid value! try again..."<<endl;
cin>>answer;
}
switch(answer)
{case 1:
{
system("cls");
cout<<"\n1. calculate and display result\n\n"<<endl;
obj.show_info();
cout<<endl;
system("pause");
break;
}
case 2:
{
system("cls");
cout<<"\n2. set images quantity\n\n"<<endl;
cout<<"amount of images - \b\b"<<endl;
cin>>img;
system("cls");
obj.set_img(img);
cout<<"\nnumber of images changed \n\n"<<endl;
system("pause");
break;
}
case 3:{
system("cls");
cout<<"\n3. set amount of people in the group \n\n"<<endl;
cout<<"amount of people - \b\b"<<endl;
cin>>img;
system("cls");
obj.set_group(group);
cout<<"\nnumber of people changed \n\n"<<endl;
system("pause");
break; }
case 4:{
system("cls");
cout<<"\n4. set individual speed\n\n"<<endl;
cout<<"amount of images - \b\b"<<endl;
cout<<"input number of people in the group\b\b"<<endl;
cin>>person;
}
system("cls");
cout<<"\n\n how many minutes person needs for editing one image - \b\b"<<endl;
cin>>speed;
system("cls");
obj.set_speed(person, speed);
cout<<"\n\n individual speed of "<<person<<"person changed \n\n"<<endl;
system("pause");
break;
}
default;
break;
}
}while
(answer!=0);
}
system("pause");
return 0;
}
Ответы (2 шт):
Я не могу овтетить на Ваш вопрос полностью, но я тут подумал, как бы это решал...
самый быстрый обработает 0.5 картин в минуту
средний - 0.33 картины в минуту
медленный - 0.25 картинв минуту
Средняя пропускная спопобность конвеера - 1.08333 картины в минуту.
1000 картин будут обработаны за 1000/1.0833333 = 923 с чем то минут.
Теперь посмотрим, что произойдет за это время.
самый быстрый обработает 461 картину за 922 минуты.
средний обработает 307 картин за 921 минуту
самый медленный - 230 картин за 920 минут
Таким образом, они обработают 998 картин, и при этом финишируют внемного разное время.
И останется необработанными 2 картины.
В этом конкретном случае - безразлично, кому из рабочих отдать их на обработку.
Отдаём их на обработку любым двум рабочим - получаем общее время обработки 924 минуты.
Теперьосталось всё это формализовать для любых наборов интервалов времени, количества картин и рабочих :-)
Ну, и у Вас там юнит-тесты просят в задании.
А вообще - достойная задача, будет интересно узнать продолжение!
Чем отличается ProcessTime и ProcessingTime? Не читая комментов не понять, а комментировать каждую строчку это антипаттерн.
Worker.ProcessTime процесс чего? Это время за которое он выполняет работу ProductionTime.
Worker.CurrentImage(текущая картинка работника)? Текущее фото работника? Семантически не вяжется, потому что CurrentImage, getCurrentImage и ProductionTime это не ответственность класса Worker.
Worker.NextWorkingInterval()... и сразу всё всем ясно (нет).
Func<Image> getCurrentImage это не ооп, а функциональное программирование. И только автор или тот кто изучил код поймет как это должно работать. А вот Worker.SetJob(ITask task); поймет любой просто прочитав.
ITask описывает работника выполняющего задание, время, статус выполнения, EventHandler выполнения и метод ITask.Update(int timeStep) вместо непонятного NextWorkingInterval(). EditedImage наследуется от ITask. Worker.SetJob(new EditedImage(Image)); и никакие комментарии не нужны, потому что всё человеческим языком.
Вместо processedIages, Tasks.
public readonly string Name;
public readonly int ProductionTime;
private List<ITask> _tasks;
public IEnumerable<ITask> Tasks => _tasks;
public int TasksCount => _tasks.Count;
public int TotalJobTime => _tasks.Select(t => t.Time).Sum();
// не обязательно
public LastTask => TasksCount > 0 ? _tasks[TasksCount-1] : null;
public bool IsFree => TasksCount > 0 ? LastTask.Status == TaskStatus.Compleated : true;
Соответственно при выдаче заданий Brigade, подписывается на событие завершения и выдает sender.Worker новое задание до тех пор пока они не закончатся.
На тему standards usage, загугли c# fields order. Сначала константы, статические и только для чтения, потом публичные и приватные поля, потом конструктор и только после него свойства!
В Brigade всё захардкодино, и не понятно почему этот класс так называется и в задаче казано:
It should work for any situation (amount of images, amount of people, individual speed)
У него должен быть конструктор с массивом рабочих(судя по названию класса) и методом выполнения массива работ Brigade.SetJubs(ITask[] tasks); и это его ответственность. Никаких Console.WriteLine в нем быть не должно. Только по завершению выполнения работ бригады можно написать Worker.TasksCount и Worker.TotalJobTime каждого работника, хотя время бригады, это время самого последнего по времени работника. Скорость каравана, это скорость самого медленного верблюда.
Юнит тест по сути задает конкретные параметры(описанные в задаче) и сравнивает их с прогнозируемыми результатами, выдавая детали того, что не сошлось если есть ошибки.