c# - ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग-एक चर के आधार पर थोड़ा भिन्न होने वाली प्रक्रियाओं में दोहराव से कैसे बचा जाए




oop (7)

मुझे खेद है कि मैंने बहुत पहले इस विषय के लिए "ऑब्जेक्ट" शब्द गढ़ा था क्योंकि यह बहुत से लोगों को कम विचार पर ध्यान केंद्रित करने के लिए मिलता है। बड़ा आइडिया है मैसेज करना

~ एलन के, मैसेजिंग पर

मैं बस RemovePunctuation रूप में RemovePunctuation Capitalise , RemovePunctuation इत्यादि को लागू RemovePunctuation जो कि text और country मापदंडों के साथ RemovePunctuation हो सकता है, और एक संसाधित पाठ लौटाएगा।

एक विशिष्ट विशेषता (यदि आप सूचियों को प्राथमिकता देते हैं, तो यह केवल एक मामूली प्रदर्शन लागत के साथ काम करेगा) समूह देशों के शब्दकोशों का उपयोग करें। उदाहरण के लिए: CapitalisationApplicableCountries और PunctuationRemovalApplicableCountries

/// Runs like a pipe: passing the text through several stages of subprocesses
public string Process(string country, string text)
{
    text = Capitalise(country, text);
    text = RemovePunctuation(country, text);
    // And so on and so forth...

    return text;
}

private string Capitalise(string country, string text)
{
    if ( ! CapitalisationApplicableCountries.ContainsKey(country) )
    {
        /* skip */
        return text;
    }

    /* do the capitalisation */
    return capitalisedText;
}

private string RemovePunctuation(string country, string text)
{
    if ( ! PunctuationRemovalApplicableCountries.ContainsKey(country) )
    {
        /* skip */
        return text;
    }

    /* do the punctuation removal */
    return punctuationFreeText;
}

private string Replace(string country, string text)
{
    // Implement it following the pattern demonstrated earlier.
}

मेरे वर्तमान कार्य में कुछ ऐसा है जो एक सामान्य प्रक्रिया है जो कि एक सामान्यीकृत प्रक्रिया है जिसे होने की आवश्यकता है, लेकिन फिर उस प्रक्रिया के विषम भाग को एक निश्चित चर के मूल्य के आधार पर थोड़ा अलग ढंग से होना चाहिए, और मैं नहीं यकीन है कि यह संभालने का सबसे सुंदर तरीका क्या है।

हम उस उदाहरण का उपयोग करेंगे जो हमारे पास आमतौर पर है, जो हम जिस देश के साथ काम कर रहे हैं, उसके आधार पर चीजों को थोड़ा अलग तरीके से कर रहे हैं।

तो मेरे पास एक वर्ग है, चलो इसे Processor कहते हैं:

public class Processor
{
    public string Process(string country, string text)
    {
        text.Capitalise();

        text.RemovePunctuation();

        text.Replace("é", "e");

        var split = text.Split(",");

        string.Join("|", split);
    }
}

सिवाय इसके कि उन कुछ कार्यों के लिए कुछ देशों को ही होना चाहिए। उदाहरण के लिए, केवल 6 देशों को पूंजीकरण कदम की आवश्यकता है। देश के आधार पर विभाजन का चरित्र बदल सकता है। देश के आधार पर केवल 'e' को बदलना आवश्यक हो सकता है।

जाहिर है आप इसे कुछ इस तरह से हल कर सकते हैं:

public string Process(string country, string text)
{
    if (country == "USA" || country == "GBR")
    {
        text.Capitalise();
    }

    if (country == "DEU")
    {
        text.RemovePunctuation();
    }

    if (country != "FRA")
    {
        text.Replace("é", "e");
    }

    var separator = DetermineSeparator(country);
    var split = text.Split(separator);

    string.Join("|", split);
}

लेकिन जब आप दुनिया के सभी संभावित देशों के साथ काम कर रहे होते हैं, तो यह बहुत बोझिल हो जाता है। और इसकी परवाह किए बिना, if कथन तर्क को पढ़ने में कठिन बनाते हैं (कम से कम, यदि आप उदाहरण से अधिक जटिल विधि की कल्पना करते हैं), और चक्रीय जटिलता बहुत तेजी से रेंगना शुरू कर देती है।

इसलिए फिलहाल मैं कुछ ऐसा करने की कोशिश कर रहा हूं:

public class Processor
{
    CountrySpecificHandlerFactory handlerFactory;

    public Processor(CountrySpecificHandlerFactory handlerFactory)
    {
        this.handlerFactory = handlerFactory;
    }

    public string Process(string country, string text)
    {
        var handlers = this.handlerFactory.CreateHandlers(country);
        handlers.Capitalier.Capitalise(text);

        handlers.PunctuationHandler.RemovePunctuation(text);

        handlers.SpecialCharacterHandler.ReplaceSpecialCharacters(text);

        var separator = handlers.SeparatorHandler.DetermineSeparator();
        var split = text.Split(separator);

        string.Join("|", split);
    }
}

हैंडलर:

public class CountrySpecificHandlerFactory
{
    private static IDictionary<string, ICapitaliser> capitaliserDictionary
                                    = new Dictionary<string, ICapitaliser>
    {
        { "USA", new Capitaliser() },
        { "GBR", new Capitaliser() },
        { "FRA", new ThingThatDoesNotCapitaliseButImplementsICapitaliser() },
        { "DEU", new ThingThatDoesNotCapitaliseButImplementsICapitaliser() },
    };

    // Imagine the other dictionaries like this...

    public CreateHandlers(string country)
    {
        return new CountrySpecificHandlers
        {
            Capitaliser = capitaliserDictionary[country],
            PunctuationHanlder = punctuationDictionary[country],
            // etc...
        };
    }
}

public class CountrySpecificHandlers
{
    public ICapitaliser Capitaliser { get; private set; }
    public IPunctuationHanlder PunctuationHanlder { get; private set; }
    public ISpecialCharacterHandler SpecialCharacterHandler { get; private set; }
    public ISeparatorHandler SeparatorHandler { get; private set; }
}

जो समान रूप से मुझे यकीन नहीं है कि मुझे पसंद है। तर्क अभी भी कुछ हद तक कारखाने के निर्माण से अस्पष्ट है और आप मूल विधि को नहीं देख सकते हैं और देखें कि क्या होता है जब "GBR" प्रक्रिया निष्पादित होती है, उदाहरण के लिए। आप शैली GbrPunctuationHandler , UsaPunctuationHandler इत्यादि में बहुत सारी कक्षाएं (इससे अधिक जटिल उदाहरणों में) UsaPunctuationHandler हैं ... जिसका अर्थ है कि आपको सभी संभावित कार्यों का पता लगाने के लिए कई अलग-अलग वर्गों को देखना होगा जो कि हो सकते हैं विराम चिह्न से निपटने के दौरान। जाहिर है मैं बयानों के साथ एक अरब के साथ एक विशाल वर्ग नहीं चाहता, लेकिन समान रूप से भिन्न भिन्न तर्क वाली 20 कक्षाएं भी क्लंकी लगती हैं।

मूल रूप से मुझे लगता है कि मैं अपने आप को OOP गाँठ के कुछ प्रकार में ले आया हूँ और इसे अछूता करने का एक अच्छा तरीका नहीं जानता। मैं सोच रहा था कि क्या वहाँ एक पैटर्न था जो इस प्रकार की प्रक्रिया में मदद करेगा?


मैं सोच रहा था कि क्या वहाँ एक पैटर्न था जो इस प्रकार की प्रक्रिया में मदद करेगा

प्रतिशोध की श्रृंखला एक ऐसी चीज है जिसे आप देख सकते हैं लेकिन OOP में कुछ बोझिल है ...

C # के साथ अधिक कार्यात्मक दृष्टिकोण के बारे में क्या?

using System;


namespace Kata {

  class Kata {


    static void Main() {

      var text = "     testing this thing for DEU          ";
      Console.WriteLine(Process.For("DEU")(text));

      text = "     testing this thing for USA          ";
      Console.WriteLine(Process.For("USA")(text));

      Console.ReadKey();
    }

    public static class Process {

      public static Func<string, string> For(string country) {

        Func<string, string> baseFnc = (string text) => text;

        var aggregatedFnc = ApplyToUpper(baseFnc, country);
        aggregatedFnc = ApplyTrim(aggregatedFnc, country);

        return aggregatedFnc;

      }

      private static Func<string, string> ApplyToUpper(Func<string, string> currentFnc, string country) {

        string toUpper(string text) => currentFnc(text).ToUpper();

        Func<string, string> fnc = null;

        switch (country) {
          case "USA":
          case "GBR":
          case "DEU":
            fnc = toUpper;
            break;
          default:
            fnc = currentFnc;
            break;
        }
        return fnc;
      }

      private static Func<string, string> ApplyTrim(Func<string, string> currentFnc, string country) {

        string trim(string text) => currentFnc(text).Trim();

        Func<string, string> fnc = null;

        switch (country) {
          case "DEU":
            fnc = trim;
            break;
          default:
            fnc = currentFnc;
            break;
        }
        return fnc;
      }
    }
  }
}

नोट: यह निश्चित रूप से सभी स्थिर होने की जरूरत नहीं है। यदि प्रोसेस क्लास को राज्य की आवश्यकता है तो आप एक इंस्टेंस्ड क्लास या आंशिक रूप से लागू फ़ंक्शन का उपयोग कर सकते हैं;)।

आप स्टार्टअप पर प्रत्येक देश के लिए प्रक्रिया का निर्माण कर सकते हैं, प्रत्येक को एक अनुक्रमित संग्रह में संग्रहीत कर सकते हैं और ओ (1) लागत के साथ आवश्यकता होने पर उन्हें पुनः प्राप्त कर सकते हैं।


आप अपनी जिम्मेदारी के बारे में कुछ जानना चाहते हैं। इसलिए देश या कल्चरइन्फो टाइप का उपयोग करें या निर्माण करें, जैसा कि अन्य उत्तरों में ऊपर बताया गया है।

लेकिन सामान्य तौर पर और बुनियादी तौर पर आपकी समस्या यह है कि आप 'प्रोसेसर' जैसे प्रक्रियात्मक निर्माणों को ले रहे हैं और उन्हें ओओ पर लागू कर रहे हैं। OO सॉफ्टवेयर में किसी व्यवसाय या समस्या डोमेन से वास्तविक विश्व अवधारणाओं का प्रतिनिधित्व करने के बारे में है। प्रोसेसर सॉफ्टवेयर के अलावा वास्तविक दुनिया की किसी भी चीज़ में अनुवाद नहीं करता है। जब भी आपके पास प्रोसेसर या प्रबंधक या राज्यपाल जैसी कक्षाएं हों, तो खतरे की घंटी बजनी चाहिए।


कुछ संस्करण पहले, पैटर्न मिलान के लिए C # swtich को पूरा समर्थन दिया गया था। ताकि "कई देशों का मिलान" मामला आसानी से हो जाए। हालांकि यह अभी भी क्षमता से कम नहीं है, एक इनपुट पैटर्न मिलान के साथ कई मामलों का मिलान कर सकता है। यह हो सकता है कि अगर एक बिट स्पष्ट स्पैम।

Npw एक स्विच आमतौर पर एक संग्रह के साथ बदला जा सकता है। आपको डेलिगेट्स और एक शब्दकोश का उपयोग करने की आवश्यकता है। प्रक्रिया के साथ बदला जा सकता है।

public delegate string ProcessDelegate(string text);

तब आप एक शब्दकोश बना सकते हैं:

var Processors = new Dictionary<string, ProcessDelegate>(){
  { "USA", EnglishProcessor },
  { "GBR", EnglishProcessor },
  { "DEU", GermanProcessor }
}

मैं फ़ंक्शन का उपयोग करता था प्रतिनिधि में हाथ करने के लिए। लेकिन आप संपूर्ण कोड प्रदान करने के लिए लैम्बडा सिंटैक्स का उपयोग कर सकते हैं। इस तरह आप किसी अन्य बड़े संग्रह की तरह ही उस पूरे संग्रह को छिपा सकते हैं। और कोड एक साधारण खोज बन जाता है:

ProcessDelegate currentProcessor = Processors[country];
string processedString = currentProcessor(country);

वे बहुत ज्यादा दो विकल्प हैं। आप मिलान के लिए तार के बजाय गणना का उपयोग करने पर विचार कर सकते हैं, लेकिन यह एक मामूली विवरण है।


मुझे लगता है कि देशों की जानकारी कोड में नहीं, डेटा में रखनी चाहिए। इसलिए एक CountryInfo वर्ग या CapitalisationApplicableCountries शब्दकोश के बजाय, आप प्रत्येक देश के लिए एक रिकॉर्ड के साथ एक डेटाबेस और प्रत्येक प्रसंस्करण कदम के लिए एक क्षेत्र हो सकते हैं, और फिर प्रसंस्करण किसी दिए गए देश के लिए क्षेत्रों के माध्यम से जा सकते हैं और तदनुसार प्रक्रिया कर सकते हैं। तब रखरखाव मुख्य रूप से डेटाबेस में होता है, नए कोड के साथ केवल तभी आवश्यक होता है जब नए चरणों की आवश्यकता होती है, और डेटा डेटाबेस में मानव पठनीय हो सकता है। यह मानता है कि चरण स्वतंत्र हैं और एक-दूसरे के साथ हस्तक्षेप नहीं करते हैं; अगर ऐसा नहीं है तो चीजें जटिल हैं।


मैं शायद (आपके उपयोग-मामले के विवरण के आधार पर) Country को एक स्ट्रिंग के बजाय "वास्तविक" वस्तु होने के साथ जाऊंगा। कीवर्ड "बहुरूपता" है।

तो मूल रूप से यह इस तरह दिखेगा:

public interface Country {
   string Process(string text);
}

फिर आप उन देशों के लिए विशिष्ट देश बना सकते हैं जिनकी आपको आवश्यकता है। नोट: आपको सभी देशों के लिए Country ऑब्जेक्ट बनाने की आवश्यकता नहीं है, आपके पास LatinlikeCountry , या यहां तक ​​कि GenericCountry । वहां आप जो कर सकते हैं, उसे एकत्र कर सकते हैं, यहां तक ​​कि दूसरों को फिर से उपयोग करना, जैसे:

public class France {
   public string Process(string text) {
      return new GenericCountry().process(text)
         .replace('a', 'b');
   }
}

या इसी के समान। Country वास्तव में Language हो सकता है, मैं उपयोग-मामले के बारे में निश्चित नहीं हूं, लेकिन मुझे आपको बात मिल जाएगी।

इसके अलावा, पाठ्यक्रम की विधि Process() नहीं होनी चाहिए Process() यह वह चीज होनी चाहिए जिसकी आपको वास्तव में जरूरत है। जैसे Words() या जो भी हो।


शायद आपके पास प्रति देश एक Processor हो सकता है?

public class FrProcessor : Processor {
    protected override string Separator => ".";

    protected override string ProcessSpecific(string text) {
        return text.Replace("é", "e");
    }
}

public class UsaProcessor : Processor {
    protected override string Separator => ",";

    protected override string ProcessSpecific(string text) {
        return text.Capitalise().RemovePunctuation();
    }
}

और प्रसंस्करण के सामान्य भागों को संभालने के लिए एक आधार वर्ग:

public abstract class Processor {
    protected abstract string Separator { get; }

    protected virtual string ProcessSpecific(string text) { }

    private string ProcessCommon(string text) {
        var split = text.Split(Separator);
        return string.Join("|", split);
    }

    public string Process(string text) {
        var s = ProcessSpecific(text);
        return ProcessCommon(s);
    }
}

इसके अलावा, आपको अपने रिटर्न प्रकारों को फिर से तैयार करना चाहिए क्योंकि यह संकलन नहीं करेगा जैसा कि आपने उन्हें लिखा है - कभी-कभी एक string विधि कुछ भी वापस नहीं करती है।







oop