![플라이웨이트](/images/patterns/cards/flyweight-mini.png?id=422ca8d2f90614dce810a8812c626698)
C#으로 작성된 플라이웨이트
플라이웨이트는 구조 패턴이며 프로그램들이 객체들의 메모리 소비를 낮게 유지하여 방대한 양의 객체들을 지원할 수 있도록 합니다.
이 패턴은 여러 객체 사이의 객체 상태를 공유하여 위를 달성합니다. 다르게 설명하자면 플라이웨이트는 다른 객체들이 공통으로 사용하는 데이터를 캐싱하여 RAM을 절약합니다.
복잡도:
인기도:
사용 사례들: 플라이웨이트 패턴의 유일한 목적은 메모리 섭취를 최소화하는 것입니다. 당신의 프로그램이 RAM 부족으로 문제를 겪지 않는다면 당분간 이 패턴을 무시할 수 있습니다.
식별: 플라이웨이트는 새로운 객체들 대신 캐싱 된 객체들을 반환하는 생성 메서드의 유무로 식별될 수 있습니다.
개념적인 예시
이 예시는 플라이웨이트의 구조를 보여주고 다음 질문에 중점을 둡니다:
- 패턴은 어떤 클래스들로 구성되어 있나요?
- 이 클래스들은 어떤 역할을 하나요?
- 패턴의 요소들은 어떻게 서로 연관되어 있나요?
Program.cs: 개념적인 예시
using System;
using System.Collections.Generic;
using System.Linq;
// Use Json.NET library, you can download it from NuGet Package Manager
using Newtonsoft.Json;
namespace RefactoringGuru.DesignPatterns.Flyweight.Conceptual
{
// The Flyweight stores a common portion of the state (also called intrinsic
// state) that belongs to multiple real business entities. The Flyweight
// accepts the rest of the state (extrinsic state, unique for each entity)
// via its method parameters.
public class Flyweight
{
private Car _sharedState;
public Flyweight(Car car)
{
this._sharedState = car;
}
public void Operation(Car uniqueState)
{
string s = JsonConvert.SerializeObject(this._sharedState);
string u = JsonConvert.SerializeObject(uniqueState);
Console.WriteLine($"Flyweight: Displaying shared {s} and unique {u} state.");
}
}
// The Flyweight Factory creates and manages the Flyweight objects. It
// ensures that flyweights are shared correctly. When the client requests a
// flyweight, the factory either returns an existing instance or creates a
// new one, if it doesn't exist yet.
public class FlyweightFactory
{
private List<Tuple<Flyweight, string>> flyweights = new List<Tuple<Flyweight, string>>();
public FlyweightFactory(params Car[] args)
{
foreach (var elem in args)
{
flyweights.Add(new Tuple<Flyweight, string>(new Flyweight(elem), this.getKey(elem)));
}
}
// Returns a Flyweight's string hash for a given state.
public string getKey(Car key)
{
List<string> elements = new List<string>();
elements.Add(key.Model);
elements.Add(key.Color);
elements.Add(key.Company);
if (key.Owner != null && key.Number != null)
{
elements.Add(key.Number);
elements.Add(key.Owner);
}
elements.Sort();
return string.Join("_", elements);
}
// Returns an existing Flyweight with a given state or creates a new
// one.
public Flyweight GetFlyweight(Car sharedState)
{
string key = this.getKey(sharedState);
if (flyweights.Where(t => t.Item2 == key).Count() == 0)
{
Console.WriteLine("FlyweightFactory: Can't find a flyweight, creating new one.");
this.flyweights.Add(new Tuple<Flyweight, string>(new Flyweight(sharedState), key));
}
else
{
Console.WriteLine("FlyweightFactory: Reusing existing flyweight.");
}
return this.flyweights.Where(t => t.Item2 == key).FirstOrDefault().Item1;
}
public void listFlyweights()
{
var count = flyweights.Count;
Console.WriteLine($"\nFlyweightFactory: I have {count} flyweights:");
foreach (var flyweight in flyweights)
{
Console.WriteLine(flyweight.Item2);
}
}
}
public class Car
{
public string Owner { get; set; }
public string Number { get; set; }
public string Company { get; set; }
public string Model { get; set; }
public string Color { get; set; }
}
class Program
{
static void Main(string[] args)
{
// The client code usually creates a bunch of pre-populated
// flyweights in the initialization stage of the application.
var factory = new FlyweightFactory(
new Car { Company = "Chevrolet", Model = "Camaro2018", Color = "pink" },
new Car { Company = "Mercedes Benz", Model = "C300", Color = "black" },
new Car { Company = "Mercedes Benz", Model = "C500", Color = "red" },
new Car { Company = "BMW", Model = "M5", Color = "red" },
new Car { Company = "BMW", Model = "X6", Color = "white" }
);
factory.listFlyweights();
addCarToPoliceDatabase(factory, new Car {
Number = "CL234IR",
Owner = "James Doe",
Company = "BMW",
Model = "M5",
Color = "red"
});
addCarToPoliceDatabase(factory, new Car {
Number = "CL234IR",
Owner = "James Doe",
Company = "BMW",
Model = "X1",
Color = "red"
});
factory.listFlyweights();
}
public static void addCarToPoliceDatabase(FlyweightFactory factory, Car car)
{
Console.WriteLine("\nClient: Adding a car to database.");
var flyweight = factory.GetFlyweight(new Car {
Color = car.Color,
Model = car.Model,
Company = car.Company
});
// The client code either stores or calculates extrinsic state and
// passes it to the flyweight's methods.
flyweight.Operation(car);
}
}
}
Output.txt: 실행 결과
FlyweightFactory: I have 5 flyweights:
Camaro2018_Chevrolet_pink
black_C300_Mercedes Benz
C500_Mercedes Benz_red
BMW_M5_red
BMW_white_X6
Client: Adding a car to database.
FlyweightFactory: Reusing existing flyweight.
Flyweight: Displaying shared {"Owner":null,"Number":null,"Company":"BMW","Model":"M5","Color":"red"} and unique {"Owner":"James Doe","Number":"CL234IR","Company":"BMW","Model":"M5","Color":"red"} state.
Client: Adding a car to database.
FlyweightFactory: Can't find a flyweight, creating new one.
Flyweight: Displaying shared {"Owner":null,"Number":null,"Company":"BMW","Model":"X1","Color":"red"} and unique {"Owner":"James Doe","Number":"CL234IR","Company":"BMW","Model":"X1","Color":"red"} state.
FlyweightFactory: I have 6 flyweights:
Camaro2018_Chevrolet_pink
black_C300_Mercedes Benz
C500_Mercedes Benz_red
BMW_M5_red
BMW_white_X6
BMW_red_X1