C # - Nie ma zabójstwa jak przesada
Po pierwsze, drogi GiMmEtHaCoDeZ, spróbujmy rozbić twoje zadanie:
- Przeczytaj liczby
- Sortuj je
- Wyjście posortowanych liczb.
Ponieważ „Dziel i rządź” jest bardzo ważną strategią podczas pracy z problemami z oprogramowaniem, rozwiążmy je pojedynczo
1. Czytanie
Kolejną ważną kwestią w oprogramowaniu jest wszechstronność. Ponieważ nie jest określone, w jaki sposób użytkownik będzie wprowadzał liczby, może się to zdarzyć za pośrednictwem konsoli, pliku, usługi internetowej itp. Może nawet jakaś metoda, o której obecnie nie możemy myśleć. Dlatego ważne jest, aby nasze rozwiązanie było w stanie pomieścić różne rodzaje danych wejściowych. Powiedzmy, że najłatwiejszym sposobem na osiągnięcie tego jest wyodrębnienie ważnej części interfejsu
public interface IDoubleArrayReader
{
IEnumerable<double> GetDoubles();
DoubleArrayReaderType Type {get;}
}
gdzie DoubleArrayReaderType
podano wyliczenie z
public enum DoubleArrayReaderType
{
Console,
File,
Database,
Internet,
Cloud,
MockService
}
Ważne jest również, aby oprogramowanie było testowalne od podstaw, aby implementacja interfejsu była możliwa
public class MockServiceDoubleArrayReader : IDoubleArrayReader
{
IEnumerable<double> IDoubleArrayReader.GetDoubles()
{
Random r = new Random();
for(int i =0; i<=10; i++)
{
yield return r.NextDouble();
}
}
DoubleArrayReaderType IDoubleArrayReader.Type
{
get
{
return DoubleArrayReaderType.MockService;
}
}
}
Następnie logicznym pytaniem jest, skąd będziemy wiedzieć, jak załadować odpowiedni IDoubleArrayReader
kod do kodu. To proste, o ile korzystamy z prostej fabryki:
public static class DoubleArrayInputOutputFactory
{
private static Dictionary<DoubleArrayReaderType, IDoubleArrayReader> readers;
static DoubleArrayInputOutputFactory()
{
readers = new Dictionary<DoubleArrayReaderType, IDoubleArrayReader>();
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
try
{
var instance = Activator.CreateInstance(type);
if (instance is IDoubleArrayReader)
{
readers.Add((instance as IDoubleArrayReader).Type,
(instance as IDoubleArrayReader));
}
}
catch
{
continue;
}
}
}
public static IDoubleArrayReader CreateDoubleArrayReader(DoubleArrayReaderType type)
{
return readers[type];
}
}
Zauważ, że używamy refleksji do ładowania wszystkich aktywnych czytników, więc wszelkie przyszłe rozszerzenia będą automatycznie dostępne Teraz, w głównej części naszego kodu, po prostu:
IDoubleArrayReader reader = DoubleArrayInputOutputFactory
.CreateDoubleArrayReader(DoubleArrayReaderType.MockService);
var doubles = reader.GetDoubles();
2. Przetwarzanie (sortowanie)
Teraz musimy przetworzyć, tzn. Posortować uzyskane liczby. Zauważ, że kroki są całkowicie niezależne od siebie, więc dla podsystemu sortowania nie ma znaczenia, w jaki sposób wprowadzono liczby. Ponadto zachowanie podczas sortowania również może ulec zmianie, np. Może być konieczne wprowadzenie bardziej wydajnego algorytmu sortowania. Oczywiście wyodrębnimy żądane zachowanie przetwarzania w interfejsie:
public interface IDoubleArrayProcessor
{
IEnumerable<double> ProcessDoubles(IEnumerable<double> input);
DoubleArrayProcessorType Type {get;}
}
public enum DoubleArrayProcessorType
{
Sorter,
Doubler,
Tripler,
Quadrupler,
Squarer
}
A zachowanie sortowania po prostu zaimplementuje interfejs:
public class SorterDoubleArrayProcessor : IDoubleArrayProcessor
{
IEnumerable<double> IDoubleArrayProcessor.ProcessDoubles(IEnumerable<double> input)
{
var output = input.ToArray();
Array.Sort(output);
return output;
}
DoubleArrayProcessorType IDoubleArrayProcessor.Type
{
get
{
return DoubleArrayProcessorType.Sorter;
}
}
}
Oczywiście potrzebujemy fabryki do ładowania instancji przetwarzania i zarządzania nimi.
public static class DoubleArrayProcessorFactory
{
private static Dictionary<DoubleArrayProcessorType, IDoubleArrayProcessor> processors;
static DoubleArrayProcessorFactory()
{
processors = new Dictionary<DoubleArrayProcessorType, IDoubleArrayProcessor>();
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
try
{
var instance = Activator.CreateInstance(type);
if (instance is IDoubleArrayProcessor)
{
processors.Add((instance as IDoubleArrayProcessor).Type, (instance as IDoubleArrayProcessor));
}
}
catch
{
continue;
}
}
}
public static IDoubleArrayProcessor CreateDoubleArrayProcessor(DoubleArrayProcessorType type)
{
return processors[type];
}
}
3. Zapis wyników
Nie ma tu wiele do powiedzenia, ponieważ jest to proces, który odzwierciedla dane wejściowe. W rzeczywistości możemy połączyć fabryki czytania i pisania w jeden DoubleArrayInputOutputFactory
, jak poniżej:
public interface IDoubleArrayWriter
{
void WriteDoublesArray(IEnumerable<double> doubles);
DoubleArrayWriterType Type {get;}
}
public enum DoubleArrayWriterType
{
Console,
File,
Internet,
Cloud,
MockService,
Database
}
public class ConsoleDoubleArrayWriter : IDoubleArrayWriter
{
void IDoubleArrayWriter.WriteDoublesArray(IEnumerable<double> doubles)
{
foreach(double @double in doubles)
{
Console.WriteLine(@double);
}
}
DoubleArrayWriterType IDoubleArrayWriter.Type
{
get
{
return DoubleArrayWriterType.Console;
}
}
}
public static class DoubleArrayInputOutputFactory
{
private static Dictionary<DoubleArrayReaderType, IDoubleArrayReader> readers;
private static Dictionary<DoubleArrayWriterType, IDoubleArrayWriter> writers;
static DoubleArrayInputOutputFactory()
{
readers = new Dictionary<DoubleArrayReaderType, IDoubleArrayReader>();
writers = new Dictionary<DoubleArrayWriterType, IDoubleArrayWriter>();
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
try
{
var instance = Activator.CreateInstance(type);
if (instance is IDoubleArrayReader)
{
readers.Add((instance as IDoubleArrayReader).Type, (instance as IDoubleArrayReader));
}
}
catch
{
continue;
}
}
foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
try
{
var instance = Activator.CreateInstance(type);
if (instance is IDoubleArrayWriter)
{
writers.Add((instance as IDoubleArrayWriter).Type, (instance as IDoubleArrayWriter));
}
}
catch
{
continue;
}
}
}
public static IDoubleArrayReader CreateDoubleArrayReader(DoubleArrayReaderType type)
{
return readers[type];
}
public static IDoubleArrayWriter CreateDoubleArrayWriter(DoubleArrayWriterType type)
{
return writers[type];
}
}
Kładąc wszystko razem
Wreszcie nasz główny program wykorzysta całą tę wspaniałość, którą już zbudowaliśmy, więc kod będzie po prostu:
var doubles = reader.GetDoubles();
doubles = processor.ProcessDoubles(doubles);
writer.WriteDoublesArray(doubles);
gdzie na przykład możemy zdefiniować reader
, writer
a processor
za pomocą
IDoubleArrayReader reader = DoubleArrayInputOutputFactory.CreateDoubleArrayReader(DoubleArrayReaderType.MockService);
IDoubleArrayProcessor processor = DoubleArrayProcessorFactory.CreateDoubleArrayProcessor(DoubleArrayProcessorType.Sorter);
IDoubleArrayWriter writer = DoubleArrayInputOutputFactory.CreateDoubleArrayWriter(DoubleArrayWriterType.Console);