비용이 적게 드는 방향으로 빠르게 개발하게 되면 효율적으로 코드를 짜기 어렵다
내 개발 비용과 컴퓨터의 비용은 반비례하는 것 같다. 알고리즘이 그렇다.
어떠한 목록(list)에서 연산을 하는 함수를 만든다고 가정할 때 내 개발 비용이 적게 들기 위해 최악의 알고리즘으로 짜는 대신 그 알고리즘을 일반화하여 확장에 열어두고 넘어갈 때 자주 쓰는 패턴이다.
예제는 알고리즘을 다룬 것은 아니고 출력하는 함수가 있고 목록(list)의 전략(Strategy)에 따라 정방향, 역방향으로 출력할 수 있게 일반화 한 것이다.
List를 상속받은 MyList라는 Collection이 있고 MyList는 Read() 함수를 통해 아이템 (Generic)을 읽어온다. 읽어올 때 IReadTypes[]에 사전 정의되어있는 ForWardRead, BackWardRead 중 가장 처음 생성된 ForWardRead 방식이 CurrentReadType이다. Read를 하게 되면 ForWardRead 방식으로 읽어온다. Change 함수를 호출하게 되면 CurrentReadType이 ForWardRead → BackWardRead로 변경되고 Read()를 호출하면 BackWardRead 방식으로 읽어온다.
그리고 마지막으로는 해당 Collection이 수정되는 것이 아니라는 것을 보여준다.
public interface IRead<T>
{
IEnumerable<T> Read(List<T> list);
}
public class BackwardRead<T> : IRead<T> where T : class
{
public IEnumerable<T> Read(List<T> list)
{
for (int i = list.Count - 1; i >= 0; i--)
{
yield return list[i];
}
}
}
public class ForwardRead<T> : IRead<T> where T : class
{
public IEnumerable<T> Read(List<T> list)
{
for (int i = 0; i < list.Count; i++)
{
yield return list[i];
}
}
}
public class Person
{
public string Name
{
get; set;
}
public int Age
{
get; set;
}
public Person(string name, int age)
{
this.Name = name;
this.Age = age;
}
public override string ToString()
{
return $"이름: {this.Name} 나이: {this.Age}";
}
}
public class MyList<T> : IList<T> where T: class
{
public List<T> Collection { get; private set; }
public IRead<T>[] ReadTypes { get; private set; }
public IRead<T> CurrentReadType { get; private set; }
private int CurrentReadTypeIndex { get; set; } = 0;
public MyList()
{
this.ReadTypes = new IRead<T>[2] { new ForwardRead<T>(), new BackwardRead<T>() };
this.CurrentReadType = ReadTypes[CurrentReadTypeIndex];
this.Collection = new List<T>();
}
public void ChangeType()
{
CurrentReadTypeIndex++;
if (CurrentReadTypeIndex == ReadTypes.Length)
CurrentReadTypeIndex = 0;
this.CurrentReadType = ReadTypes[CurrentReadTypeIndex];
}
public IEnumerable<T> Read() => this.CurrentReadType.Read(this.Collection);
public T this[int index] { get => Collection[index]; set => Collection[index] = value; }
public int Count => Collection.Count;
public bool IsReadOnly => true;
public void Add(T item) => Collection.Add(item);
public void Clear() => Collection.Clear();
public bool Contains(T item) => Collection.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => Collection.CopyTo(array, arrayIndex);
public IEnumerator<T> GetEnumerator() => Collection.GetEnumerator();
public int IndexOf(T item) => Collection.IndexOf(item);
public void Insert(int index, T item) => Collection.Insert(index, item);
public bool Remove(T item) => Collection.Remove(item);
public void RemoveAt(int index) => Collection.RemoveAt(index);
IEnumerator IEnumerable.GetEnumerator() => Collection.GetEnumerator();
}
class Program
{
static void Main(string[] args)
{
MyList<Person> people = new MyList<Person>()
{
new Person("최용국", 28),
new Person("이은혜", 31),
new Person("이정선", 29),
new Person("안광필", 35)
};
foreach (var person in people.Read())
{
Console.WriteLine(person);
}
Console.WriteLine("=================================");
people.ChangeType();
foreach (var person in people.Read())
{
Console.WriteLine(person);
}
Console.WriteLine("=================================");
foreach (var person in people)
{
Console.WriteLine(person);
}
Console.ReadLine();
}
}