Я беру некоторый код для проекта, и я видел кучу скопированного кода в нескольких классах.Владелец очень устал от рефакторинга этого кода, но мне пришла в голову идея, которая звучит для него хорошо.
Учитывая:
Несколько классов "Client", которые НЕимеют точно такой же интерфейс, но довольно близкий:
class Client1
{
public static string FunctionA(a);
public static string FunctionB(a, b, c);
public static string FunctionC(a, b);
}
class Client2
{
public static string FunctionA(a);
public static string FunctionB(a, b, c);
public static string FunctionC(a, b);
}
class Client3
{
public static string FunctionA(a);
public static string FunctionC(a, b);
public static string FunctionD();
}
... etc
Допустим, что FunctionA
- это функция, ТОЧНО одинаковая в каждом классе.Владелец почему-то считает, что эта функция должна присутствовать в каждом классе, потому что «она может отличаться для другого клиента в будущем» (fyi: FunctionA преобразует стандартное время в военное время ... поэтому я в этом сильно сомневаюсь).
Каждый из его клиентов имеет специальный код (например, «abc» или «xyz» в файле web.config
, поэтому при обращении к коду клиента он получает правильное поведение, используя код, подобный следующему:
public static string FunctionA(string a)
{
switch(getClientCode())
{
case "abc":
return Client1.FunctionA(a);
case "xyz":
return Client2.FunctionA(a);
case "def":
return Client3.FunctionA(a);
default:
throw new Exception("code not supported");
}
}
Пусть будет известно, что я ни в коем случае не думаю, что это идеально. Я действительно боролся со своим клиентом (которому принадлежит этот код) в некоторых довольно жарких дискуссиях о принятых им решениях.с этим проектом , поэтому не стреляйте в мессенджера.
Мой клиент считает, что такой способ работы полезен, когда, скажем, я хочу реализовать нового клиента, я могу просто запуститьприложения и пройти через некоторые шаги, пока я не найду и не "исправлю" эти сгенерированные исключения. Вот почему владельцу нравится, как код настраивается таким образом. Однако примерно половина функций в каждом CКласс lient одинаков для каждого клиента ИЛИ одинаков для примерно 80% клиентов.
Я спросил его, почему у него просто нет абстрактного класса, и причина в том, что не все производные классыдолжен или реализовать любую из функций базовых классов.Кроме того, все открытые функции являются статическими (и не имеют переменных-членов), поэтому нет смысла создавать экземпляры объектов.
Мой шаблон:
Использованиеклиентские классы сверху, я хотел бы реализовать что-то вроде этого:
class Client1
{
// FunctionA is the same for each class
//public static string FunctionA(a);
public static string FunctionB(string a, string b, string c);
// Client1 and Client3 share the same code.
//public static string FunctionC(a, b);
}
class Client2
{
// FunctionA is the same for each class
//public static string FunctionA(a);
public static string FunctionB(string a, string b, string c);
public static string FunctionC(string a, string b);
}
class Client3
{
// FunctionA is the same for each class
//public static string FunctionA(a);
// Client1 and Client3 share the same code.
//public static string FunctionC(a, b);
public static string FunctionD();
}
... etc.
class DefaultClient
{
public static string FunctionA(string a);
public static string FunctionB(string a, string b, string c);
public static string FunctionC(string a, string b);
}
class ProxyUtility
{
private static string getClientCode();
public static string FunctionA(string a)
{
switch (getClientCode())
{
case "abc":
case "def":
case "xyz":
return DefaultClient.FunctionA(a);
default:
throw new Exception("code not supported");
}
}
public static string FunctionB(string a, string b, string c)
{
switch (getClientCode())
{
case "abc":
case "xyz":
return DefaultClient.FunctionB(a, b, c);
case "def":
return string.Empty; // or throw an exception since they don't support this
default:
throw new Exception("code not supported");
}
}
public static string FunctionC(string a, string b)
{
switch (getClientCode())
{
case "abc":
case "def":
return DefaultClient.FunctionC(a, b);
case "xyz":
return Client2.FunctionC(a, b);
default:
throw new Exception("code not supported");
}
}
public static string FunctionD()
{
switch (getClientCode())
{
case "abc":
case "xyz":
return string.Empty; // or throw an exception since they don't support this function.
case "def":
return Client3.FunctionD();
default:
throw new Exception("code not supported");
}
}
}
Вот блок-схема, чтобы понять, как это работает: