重构内部使用相同代码但不同方法的方法

本文关键字:方法 内部 代码 重构 | 更新日期: 2023-09-27 18:28:37

除了一行之外,我有一些方法是相同的(我在对象客户端上调用不同的方法)。我会有更多这样的方法。

除了使用反射之外,还有什么解决方案吗?

 private void initClerks(Client client)
            {
                string[] pks = client.ClerksPKS.Trim(','). Split(',');
                foreach (string pk in pks)
                {
                    string data = JObject.Parse(DBUtils.GetData(Constants.DBProcedures.GetProcedures.GetWorkerDetailsByPkid, pk))[Constants.ResponseJson.Data].ToString();
                    client.addClerk(JsonConvert.DeserializeObject<Clerk[]>(data)[0]);
                }
            }

private void initManagers(Client client)
            {
                string[] pks = client.ManagerPK.Trim(',').Split(',');

                foreach (string pk in pks)
                {
                    string data = JObject.Parse(DBUtils.GetData(Constants.DBProcedures.GetProcedures.GetWorkerDetailsByPkid, pk))[Constants.ResponseJson.Data].ToString();
                    client.addManager(JsonConvert.DeserializeObject<Manager[]>(data)[0]);
                }
            }

重构内部使用相同代码但不同方法的方法

您可以通过将操作传递到方法中来实现这一点。类似的东西

private void actOnData(Client client, string[] pks, Action<Client, string> addThing)
{
    foreach (string pk in pks)
    {
        string data = JObject.Parse(DBUtils.GetData(Constants.DBProcedures.GetProcedures.GetWorkerDetailsByPkid, pk))[Constants.ResponseJson.Data].ToString();
        addThing(client, data);
    }
}
private void initClerks(Client client)
{
    string[] pks = client.ClerksPKS.Trim(',').Split(',');
    actOnData(client,pks,(c,d) => { c.addClerk(JsonConvert.DeserializeObject<Clerk[]>(d)[0]); });
}
private void initManagers(Client client)
{
    string[] pks = client.ManagerPK.Trim(',').Split(',');
    actOnData(client, pks, (c, d) => { c.addManager(JsonConvert.DeserializeObject<Manager[]>(d)[0]); });
}

考虑到这不是外部遗留库,我建议重构客户端类以简化其API(我会更改更多内容,但让我们在某个时候停止)

伪代码:

// taking into account Client, manager all are workers
class Client
{
    // further whenever you need filter out managers use LINQ OfType<>
    List<Workers> workers;
    public void Add<T>(T worker) where T: Worker
    {
        workers.Add(client);
    }
}

参见提取方法,

private void Initialize<T>(Client client, string[] pks)
{
    foreach (string pk in pks)
    {
        string data = JObject.Parse(DBUtils.GetData(Constants.DBProcedures.GetProcedures.GetWorkerDetailsByPkid, pk))[Constants.ResponseJson.Data].ToString();
        client.Add(JsonConvert.DeserializeObject<T[]>(data)[0]);    
    }
}
private void initClerks(Client client)
{
    string[] pks = client.ClerksPKS.Trim(',').Split(',');
    Initialize<Clerk>(client, pks);
}
private void initManagers(Client client)
{
    string[] pks = client.ManagerPK.Trim(',').Split(',');
    Initialize<Manager>(client, pks);           
}

接下来,两个initClerks/initmanager看起来是多余的,只是对Initialize的内联调用(当然,如果整个代码库不比这里显示的更复杂的话)

提取方法的典型路径是查找差异并声明相应的方法参数。让我们采用你的initClerks方法,在里面找到单词Clerk。其中有3个,一个是Type,所以我们将制作一个泛型方法,其泛型参数T对应于Clerk。映射将类似于

(1) client.ClerksPKS映射到Func<Client, string>
(2) JsonConvert.DeserializeObject<Clerk[]>映射到JsonConvert.DeserializeObject<T[]>
(3) client.addClerk映射到Action<Client, T>

所以常用的方法变成

void Init<T>(Client client, Func<Client, string> getPKS, Action<Client, T> addItem)
{
    string[] pks = getPKS(client).Trim(','). Split(',');
    foreach (string pk in pks)
    {
        string data = JObject.Parse(DBUtils.GetData(Constants.DBProcedures.GetProcedures.GetWorkerDetailsByPkid, pk))[Constants.ResponseJson.Data].ToString();
        addItem(client, JsonConvert.DeserializeObject<T[]>(data)[0]);
    }
}

以及使用

private void initClerks(Client client)
{
    Init<Clerk>(client, c => c.ClerksPKS, (c, x) => c.addClerk(x));
}
private void initManagers(Client client)
{
    Init<Manager>(client, c => c.ManagerPK, (c, x) => c.addManager(x));
}

创建基类以在其基本Init方法中添加公共逻辑。则在实现BaseClientInitializer的类中重写Insert方法。这种设计模式被称为模板方法。

public abstract class BaseClientInitializer
  {
    private string[] keys;
    public BaseClientInitializer(string[] keys)
    {
      this.keys = keys;
    }
public abstract void Insert(string data);
public void Init()
{
  foreach (string pk in keys)
  {
    var data = JObject.Parse(DBUtils.GetData(Constants.DBProcedures.GetProcedures.GetWorkerDetailsByPkid, pk))[
        Constants.ResponseJson.Data].ToString();
    this.Insert(data);
  }
}   

 }
public class Clerks : BaseClientInitializer
  {
    private Client client;
    public Clerks(Client client) : base(client.ClerksPKS.Trim(','). Split(','))
    {
      this.client = client;
    }
    public override void Insert(string data)
    {
      client.addClerk(JsonConvert.DeserializeObject<Clerk[]>(data)[0]);
    }
  }
private void initClerks(Client client)
{
     var clerksInitializer = new ClerksInitializer(client);
    clerksInitializer.Init();
}

对init管理器执行同样的操作。区别不仅在于插入方法,pks数组也不同:客户端。职员PKS。修剪(',')。拆分(',])-适用于职员和客户。ManagerPK.Trim(',').Split(','')用于经理。所以简单的提取方法不会正确工作。