Va bene per avvolgere un singleton?

1

Sto usando SignalR con StackExchange Redis. Cosa raccolgo dal documento di utilizzo di base è il modo per implementare questo utilizzando un singleton. Non ho mai usato questo patter prima d'ora. La mia classe ha questo aspetto:

public class RedisInstance
{
    public static readonly RedisInstance Instance = new RedisInstance();
    public static ConnectionMultiplexer Redis;

    public RedisInstance()
    {
        Redis = ConnectionMultiplexer.Connect("localhost");
    }
}

L'ho usato in questo modo

public class DashHub : Hub
{
    public void MapUser(int userId)
    {
        var user = new AppUser() {Id = userId, ConnectionIds = new List<string>() {Context.ConnectionId } };
        var db = RedisInstance.Redis.GetDatabase();

        var userJson = JsonConvert.SerializeObject(user);

        db.StringSet(userId.ToString(), userJson);
    }

Ma pensavo che questo fosse piuttosto restringente se lo costruissi e in futuro volessi usare qualcosa di diverso da Redis, quindi stavo per farlo

public class DatabaseRepository
{
    IDatabase db;

    public DatabaseRepository()
    {
        this.db = RedisInstance.Redis.GetDatabase();
    }

    public void Insert(string key, string value)
    {
        db.StringSet(key, value);
    }
}

e quindi fai riferimento a ciò nelle altre mie classi. Sto usando questi modelli appropriatamente qui? Ci sono problemi con l'utilizzo di un singleton in questo modo? Questo può sembrare semplice ma sto solo imparando questo e voglio esserne sicuro.

    
posta ygetarts 04.08.2016 - 22:34
fonte

3 risposte

1

Quando il tuo codice ha un singleton, suppongo che chiunque possa usare quel singleton. Altrimenti, non è un singleton (una classe che ha per coincidenza solo un'istanza non è un singleton. Una classe che per design può avere solo un'istanza è un singleton).

No, tu dici di "avvolgere un singleton". Il wrapper sarebbe di nuovo un singleton. (Ovviamente è possibile avere una classe con molte istanze che contengono ciascuna un riferimento allo stesso singleton, ma che non sarebbe un wrapper).

Quindi hai un singleton e un singleton wrapper che dietro le quinte si riferisce allo stesso singleton. Sarei preoccupato che la possibilità di usare lo stesso singleton in due modi diversi causerebbe confusione.

    
risposta data 05.09.2016 - 00:35
fonte
0

Prova qualcosa come (pseudo codice):

public Interface IKeyValueRepository
{
    void Insert(string key, string value);
     //Put other methods here
}

//Redis Implementation
public RedisRepository : IKeyValueRepository
{
    private static ConnectionMultiplexer _redis;

    public RedisRepository ()
    {
         _redis = ConnectionMultiplexer.Connect("localhost");
    }

    public void Insert(string key, string value)
    {
        var db = _redis.GetDatabase();       
        db.StringSet(key, value);
    }
    //And so forth
}

Quindi dovresti essere in grado di scambiare le cose abbastanza facilmente e prendere in giro anche il repository.

    
risposta data 04.08.2016 - 23:13
fonte
0

Non ho avuto molta esperienza nell'usare redis, quindi questo codice potrebbe non essere corretto al 100%. Ma sarebbe meglio se tu usassi l'iniezione di dipendenza per gestire il tuo singleton. In questo modo non devi codificare la tua classe per essere un singleton e se vuoi / devi cambiarlo in qualsiasi momento sarà molto semplice. ad esempio

DI layer

builder.RegisterType<RedisInstance>().As<IRedisInstance>().SingleInstance();
builder.RegisterType<DatabaseRepository>().As<IDatabaseRepository>();

Istanza di Redis

public class RedisInstance : IRedisInstance
{
    public static ConnectionMultiplexer Redis;

    public RedisInstance()
    {
        Redis = ConnectionMultiplexer.Connect("localhost");
    }
}

DatabaseRepository

public class DatabaseRepository: IDatabaseRepository
{
   private readonly IRedisInstance db;

   public DatabaseRepository(IRedisInstance redisInstance)
   {
      this.db = redisInstance;
   }

   public void Insert(string key, string value)
   {
     this.db.Redis.StringSet(key, value);
   }
}

Utilizzo

public class DashHub : Hub
{
  private readonly IDatabaseRepository repo;

  public DashHub(IDatabaseRepository repo)
  {
   this.repo = repo;
   }
    public void MapUser(int userId)
    {
        var db = this.repo.Insert("blah", "blah");
    }
}

Ulteriori

Non sono sicuro del motivo per cui vorresti che i tuoi dati siano in modalità singleton come vorresti che la tua connessione si chiudesse e che un singleton significasse che più richieste accederanno alla stessa istanza. Quindi ora puoi cambiare l'iniezione della dipendenza in modo che sia così:

builder.RegisterType<RedisInstance>().As<IRedisInstance>().InstancePerLifetimeScope();
    
risposta data 05.08.2016 - 11:31
fonte

Leggi altre domande sui tag