Definition
Use sharing to support large numbers of fine-grained objects efficiently.
- Split heavy objects into what can be shared (flyweight / template / intrinsic data) and what to be configured (context / extrinsic data)
- The heavy object can be generated on the fly from the flyweight object and the context
- Reduce the memory cost of working with large numbers of very small objects
Flyweight vs Singleton
- flyweight pattern is acting like a common template that can be configured as per the need
- singleton pattern allows to reuse an existing object
Multithreading
Same problem and remedy as the Singleton pattern.
Exemple
User.cs
|
public class User
{
public string Name { get; set; }
public override string ToString() => $"Simple user: {Name}";
}
|
Administrator.cs
|
public class Administrator : User
{
public override string ToString() => $"Admin user: {Name}";
}
|
UserFactory.cs
|
public class UserFactory
{
IDictionary<UserType, User> userTemplatesByUserType = new Dictionary<UserType, User>();
public User GetUserFromFactory(UserType userType)
{
User userTemplate = null;
if (userTemplatesByUserType.ContainsKey(userType))
{
userTemplate = userTemplatesByUserType[userType];
}
else
{
switch (userType)
{
case UserType.User:
userTemplate = new User();
userTemplatesByUserType.Add(UserType.User, userTemplate);
break;
case UserType.Administrator:
userTemplate = new Administrator();
userTemplatesByUserType.Add(UserType.Administrator, userTemplate);
break;
case UserType.Guest:
userTemplate = new Guest();
userTemplatesByUserType.Add(UserType.Guest, userTemplate);
break;
default:
throw new Exception($"Unknown user type {userType}.");
}
}
return userTemplate;
}
}
|
|
var userFactory = new UserFactory();
var user = userFactory.GetUserFromFactory(UserType.User);
user.Name = "Nicolas";
Console.WriteLine(user);
for (var i = 0; i < 10; i++)
{
// call only once the Administrator ctor then reuse the instance
user = userFactory.GetUserFromFactory(UserType.Administrator);
user.Name = $"Admin{i}";
Console.WriteLine(user);
}
|