0

I have a project which works on translating languages from one to another and on the UI layer I can only work with one type of Entity class with instantiating it tightly coupled as following;

EnglishTurkish word = new EnglishTurkish()
 {
      Word = inputText.Text.ToLower(),
      Translation = translatedText.Text.ToLower()
 };
 EnglishTurkishManager englishTurkishManager = new EnglishTurkishManager(new SlEnglishTurkishDal());

Users can choose the source and target language and if the source language is 'English' and the target is 'Turkish' then the code above works fine. But let's assume that the user has chosen 'English' to 'French', then I'd need to instantiate as following;

  EglishFrench word = new EglishFrench()
  {
       Word = inputText.Text.ToLower(),
       Translation = translatedText.Text.ToLower()
  };
  EglishFrenchhManager englishFrenchManager = new EnglishFrenchManager(new SlEnglishFrenchDal());

I can handle instantiating of entity class with Factory design pattern as following;

public class TableInstanceFactory
    {
        public static IEntity GenerateTableInstance(string tableName)
        {
            switch (tableName)
            {
                case "TurkishEnglish":
                    return new TurkishEnglish();
                default:
                    break;
            }
        }
    }

But this will require so much effort to put all possible table names in the switch statement and somehow I feel like this is not the correct way to do it. Another problem is how to handle the generation of classes with the extension of 'Manager' and 'Dal'(like EglishFrenchhManager and SlEnglishFrenchDal). Is there a better way to do to handle it dynamically?

zalky
  • 659
  • 1
  • 7
  • 12
  • Why do you need a new type for each combination of languages? How about having `FromLanguage` and `ToLanguage` properties instead? – Xerillio Apr 17 '21 at 18:52
  • @Xerillio It's because I store each language pair in a different table in the database, so I need to create a related entity class instance based on user choice. – zalky Apr 17 '21 at 19:04
  • Is there a reason to have a separate table for each pair? It seems to me the entities would all be identical apart from their names – Xerillio Apr 17 '21 at 19:16
  • That's correct, each table will store the same column names. The reason for having a separate table for each pair is showing related language pair words to the user based on the selection of language, basically not showing all languages at once. – zalky Apr 17 '21 at 20:22

1 Answers1

0

I'm assuming you're using EF Core here. I don't really know what EnglishTurkishManager and SlEnglishTurkishDal are doing, so I'm guessing how those classes could look like here. I'd probably do something along the lines of the following:

abstract class BaseDictionaryEntry
{
    public string Word { get; set; }
    public string Translation { get; set; }
}

class EnglishTurkish : BaseDictionaryEntry { }
class EnglishFrench : BaseDictionaryEntry { }

// Instead of SlEnglishTurkishDal
class SlDictionaryDal
{
    public void AddTranslation(BaseDictionaryEntry entity)
    {
        _dbContext.Add(entity);
        _dbContext.SaveChanges();
    }
}

// Instead of EnglishTurkishManager
class DictionaryManager
{
    private readonly SlDictionaryDal _myDal;
    public DictionaryManager(SlDictionaryDal dal)
    {
        _myDal = dal;
    }
    
    public void SaveTranslation(string langFrom, string langTo, string word, string trans)
    {
        var entity = DictionaryFactory.CreateEntity(langFrom, langTo, word, trans);
        _myDal.AddTranslation(entity);
    }
}

You factory could look like this then:

static class DictionaryFactory
{
    // Inspired from https://stackoverflow.com/a/17680332/3034273
    private static readonly Type[] DictEntryTypes =
        (from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
            from assemblyType in domainAssembly.GetTypes()
            where assemblyType.IsSubclassOf(typeof(BaseDictionaryEntry))
            select assemblyType).ToArray();
    
    public static BaseDictionaryEntry CreateEntity(string langFrom, string langTo, string word, string trans)
    {
        var dictLookupName = $"{langFrom}{langTo}".ToLowerInvariant();
        var matchingType = DictEntryTypes.FirstOrDefault(t => t.Name.ToLowerInvariant() == dictLookupName);
        if (matchingType == null)
            throw new InvalidOperationException($"No dictionary exists matching the language pair {langFrom}{langTo}");
        
        var entry = (BaseDictionaryEntry)Activator.CreateInstance(matchingType);
        entry.Word = word;
        entry.Translation = trans;
        return entry;
    }
}

Sample fiddle

As you can see, there's a bit of reflection going on, which IMO is a bit ugly. Alternatively, I'd suggest you rethink how you are storing these translations. If you used one table instead of one per "dictionary", you could make the above much simpler.

Xerillio
  • 4,855
  • 1
  • 17
  • 28