Flyweight Pattern

The share pattern is a structural pattern that efficiently supports a large number of fine-grained objects in a shared manner. By overusing existing objects in memory, the system reduces the performance cost of creating object instances.

The meta-share pattern attempts to reuse existing objects of the same kind, creating a new object if no match is found, and returning directly if one is found.

role

1. Abstract Flyweight

It is the abstract base class of all concrete metaclasses, specifying the common interface to be implemented for its subclasses.

2. Concrete Flyweight

The concrete metaclass implements the interface specified by the abstract metaclass.

3. FlyweightFactoiy

The privilege factory class is responsible for creating and managing the privilege objects.

The sample



The FlyweightPattern namespace contains the IConnection interface as an abstract privilege, the Connection class as a concrete privilege, and the ConnectionFactory class as a privilege factory. This example uses the meta schema to share database connections.

public interface IConnection {

    void Print();

}
Copy the code

IConnection interface, which contains a print method.

public class Connection : IConnection {
 
    private string _connectionString = null;
 
    public Connection(string connectionString) {
        _connectionString = connectionString;
        Thread.Sleep(1000);
        Console.WriteLine("It took 1 second(s) to create a connection!");
    }
 
    public void Print() {
        Console.WriteLine($"Database connection is {_connectionString}");
        Console.WriteLine("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --"); }}Copy the code

Connection class, defining database connections (demo).

public class ConnectionFactory {

    private Dictionary<string, IConnection> _connections = null;

    private string _connectionString = null;

    public ConnectionFactory() {
        _connections = new Dictionary<string, IConnection>();
    }

    public IConnection CreateConnection(string connectionString) {
        if(! _connections.ContainsKey(connectionString)) { Console.WriteLine("Creating a new connection!");
            IConnection connection = new Connection(connectionString);
            _connections.Add(connectionString, connection);
            return connection;
        }
        else {
            Console.WriteLine("Return an exist connection!");
            var connection = _connections[connectionString] as IConnection;
            returnconnection; }}}Copy the code

The ConnectionFactory class, the database ConnectionFactory, maintains internal references to all connections, and the CreateConnection method returns when it finds that a connection exists, or creates a new connection and maintains it in the list if none exists.

Note: During actual development, HashCode should be used to check whether the database connection exists.

public class Program {

    private static ConnectionFactory _factory = null;

    private static List<string> _connections = null;

    private static IConnection _connection = null;

    private static void Print(int index) {
        if (index > _connections.Count - 1) {
            Console.WriteLine("Index Out Of Range Exception!");
            return;
        }
        _connection = _factory.CreateConnection(_connections[index]);
        _connection.Print();
    }

    public static void Main(string[] args) {
        _connections = new List<string> {
            "Server=Aron1; Database=pubs; \n" + "Uid=uid; Pwd=password;"."Provider=sqloledb; Data Source=Aron1; \n" + "User Id=uid; Password=password;"."Data Source = 192.168.0.1, 1433; \n" + "UserID=uid; Password=password;"
        };

        _factory = new ConnectionFactory();

        Print(0);
        Print(1);
        Print(2);
        Print(1);
        Print(3); Console.ReadKey(); }}Copy the code

This is the caller’s code, and here is the output of the case:

Creating a new connection!
It took 1 second(s) to create a connection!
Database connection isServer=Aron1; Database=pubs; Uid=uid; Pwd=password; ------------------------------------------------------- Creating anew connection!
It took 1 second(s) to create a connection!
Database connection isProvider=sqloledb; Data Source=Aron1; User Id=uid; Password=password; ------------------------------------------------------- Creating anew connection!
It took 1 second(s) to create a connection!
Database connection is Data Source=192.168. 01..1433; UserID=uid; Password=password; ------------------------------------------------------- Return an exist connection! Database connectionisProvider=sqloledb; Data Source=Aron1; User Id=uid; Password=password; ------------------------------------------------------- Index Out Of Range Exception!Copy the code

advantages

1. Reduce the number of objects in the system, thus reducing the pressure on memory brought by fine-grained objects in the system.

disadvantages

1. In order to make objects shareable, some state needs to be externalized, which makes the logic of the program more complex and complicates the system; 2. The share mode externalizes the state of the share object, while reading the external state makes the run time slightly longer.

Usage scenarios

1. A system has a large number of objects; 2. These objects consume a lot of memory; 3. Most of the state in these objects can be externalized; 4. These objects can be divided into groups according to their internal state. When external objects are removed from the group, each group can be replaced by only one object. The software system does not depend on the identity of these objects.