Самый близкий шаблон проектирования, о котором я могу подумать, это шаблон Цепочки ответственности.
Идея состоит в том, что:
- Вы строите цепочку объектов (серверов)
- Пусть объект (сервер) обработает запрос
- Если это невозможно, передайте запрос по цепочке
Код:
// Server interface
public interface IServer
{
object FetchData(object param);
}
public class ServerProxyBase: IServer
{
// Successor.
// Alternate server to contact if the current instance fails.
public ServerBase AlternateServerProxy { get; set; }
// Interface
public virtual object FetchData(object param)
{
if (AlternateServerProxy != null)
{
return AlternateServerProxy.FetchData(param);
}
throw new NotImplementedException("Unable to recover");
}
}
// Server implementation
public class ServerProxy : ServerProxyBase
{
// Interface implementation
public override object FetchData(object param)
{
try
{
// Contact actual server and return data
// Remoting/WCF code in here...
}
catch
{
// If fail to contact server,
// run base method (attempt to recover)
return base.FetchData(param);
}
}
}
public class Client
{
private IServer _serverProxy;
public Client()
{
// Wire up main server, and its failover/retry servers
_serverProxy = new ServerProxy("mainserver:2712")
{
AlternateServerProxy = new ServerProxy("failover1:2712")
{
AlternateServerProxy = new ServerProxy("failover2:2712")
}
};
}
}
В этом примере подключается цепочка из 3 серверов (mainserver, failover1, failover2).
При вызове FetchData()
всегда будет пытаться перейти на mainserver
.
В случае неудачи он попытается failover1
, а затем failover2
, прежде чем, наконец, сгенерировать исключение.
Если бы это зависело от меня, я бы не стал использоватьчто-то быстрое и грязное, такое как:
public class FailoverServerProxy: IServer
{
private readonly List<ServerProxy> _servers;
public FailoverServerProxy RegisterServer(Server server)
{
_servers.Add(server);
return this;
}
// Implement interface
public object FetchData(object param)
{
foreach(var server in _servers)
{
try
{
return server.FetchData(param);
}
catch
{
// Failed. Continue to next server in list
continue;
}
}
// No more servers to try. No longer able to recover
throw new Exception("Unable to fetch data");
}
}
public class Client
{
private IServer _serverProxy;
public Client()
{
// Wire up main server, and its failover/retry servers
_serverProxy = new FailoverServerProxy()
.RegisterServer("mainserver:2712")
.RegisterServer("failover1:2712")
.RegisterServer("failover2:2712");
}
}
Я думаю, что оно заимствует идеи из других шаблонов, таких как Фасад, Стратегия и Прокси.
Но мои мотивы просто:
- Наименьшее влияние на существующие классы (т. Е. Отсутствие дополнительных свойств в классе
Server
) - Разделение задач:
- Центральный класс для логики отработки отказа / восстановления сервера.
- Сохраните реализацию аварийного переключения / восстановления скрытой от клиента / сервера.