ক্যাচিং পরিচালনা করতে কীভাবে কোনও ক্লাসে এসআরপি লঙ্ঘন করা এড়ানো যায়?


12

দ্রষ্টব্য: কোড নমুনা সি # তে লিখিত হয়েছে, তবে এটি কোনও বিষয় নয়। আমি ট্যাগ হিসাবে সি # রেখেছি কারণ আমি এর চেয়ে বেশি অ্যাপোপিয়েট পাই না। এটি কোড কাঠামো সম্পর্কে।

আমি ক্লিন কোড পড়ছি এবং আরও ভাল প্রোগ্রামার হওয়ার চেষ্টা করছি।

আমি প্রায়শই নিজেকে একক দায়িত্বের নীতি অনুসরণ করার জন্য লড়াই করতে দেখি (শ্রেণি এবং ক্রিয়াকলাপগুলি কেবল একটি কাজ করা উচিত) বিশেষত ফাংশনে। হয়তো আমার সমস্যাটি হ'ল "একটি জিনিস" ভাল সংজ্ঞাযুক্ত নয়, তবে এখনও ...

একটি উদাহরণ: আমার কাছে একটি ডাটাবেসে ফ্লাফিজির একটি তালিকা রয়েছে। ফ্লাফি কী তা আমরা যত্ন করি না। আমি ফ্লাফির পুনরুদ্ধার করার জন্য একটি ক্লাস চাই। তবে কিছু যুক্তি অনুসারে ফ্লফি বদলে যেতে পারে। কিছু যুক্তির উপর নির্ভর করে এই শ্রেণিটি ক্যাশে থেকে ডেটা ফেরত দেবে বা ডাটাবেস থেকে সর্বশেষটি পাবে। আমরা বলতে পারি যে এটি ফ্লফিগুলি পরিচালনা করে এবং এটি একটি জিনিস। এটিকে সহজ করার জন্য, আসুন বলি লোড হওয়া ডেটা এক ঘন্টার জন্য ভাল, এবং তারপরে অবশ্যই এটি পুনরায় লোড করা উচিত।

class FluffiesManager
{
    private Fluffies m_Cache;
    private DateTime m_NextReload = DateTime.MinValue;
    // ...
    public Fluffies GetFluffies()
    {
        if (NeedsReload())
            LoadFluffies();

        return m_Cache;
    }

    private NeedsReload()
    {
        return (m_NextReload < DateTime.Now);
    }

    private void LoadFluffies()
    {
        GetFluffiesFromDb();
        UpdateNextLoad();
    }

    private void UpdateNextLoad()
    {
        m_NextReload = DatTime.Now + TimeSpan.FromHours(1);
    }
    // ...
}

GetFluffies()আমার কাছে ঠিক আছে ব্যবহারকারী কিছু fluffies জন্য জিজ্ঞাসা, আমরা তাদের সরবরাহ। প্রয়োজনে তাদের ডিবি থেকে পুনরুদ্ধার করতে যাওয়া, তবে এটি ফ্লাফিগুলি পাওয়ার একটি অংশ হিসাবে বিবেচনা করা যেতে পারে (অবশ্যই এটি কিছুটা সাবজেক্টিভ)।

NeedsReload()ঠিক মনে হচ্ছে। আমাদের যদি ফ্লফিগুলি পুনরায় লোড করতে হয় তবে তা পরীক্ষা করে দেখুন। আপডেটনেক্সটলড ঠিক আছে। পরবর্তী পুনরায় লোডের জন্য সময় আপডেট করে। এটি অবশ্যই একটি একক জিনিস।

যাইহোক, আমি অনুভব করি যা করা হয় LoadFluffies()তা একক জিনিস হিসাবে বর্ণনা করা যায় না। এটি ডেটাবেস থেকে ডেটা পাচ্ছে এবং এটি পরবর্তী পুনরায় লোডের সময় নির্ধারণ করছে। তর্ক করা শক্ত যে পরের পুনরায় লোডের জন্য সময় গণনা করা ডেটা পাওয়ার অংশ। যাইহোক, আমি এটি করার আরও ভাল উপায় খুঁজে পাচ্ছি না (ফাংশনটির নামকরণটি LoadFluffiesAndScheduleNextLoadআরও ভাল হতে পারে তবে এটি সমস্যাটিকে আরও স্পষ্ট করে তোলে)।

এসআরপি অনুযায়ী এই ক্লাসটি সত্যিই লেখার জন্য কি কোনও মার্জিত সমাধান রয়েছে? আমি কি খুব পেডেন্টিক হচ্ছি?

অথবা আমার ক্লাসটি সত্যই কেবল একটি কাজ করছে না?


3
"সি # তে লিখিত, তবে এটির কোনও বিবেচনা করা উচিত না", "এটি কোড কাঠামোর বিষয়ে", "উদাহরণ হিসাবে:" এর ভিত্তিতে ভিত্তি করে, "আমরা একটি ফ্লফি কী তা বিবেচনা করি না", "এটিকে সহজ করতে, বলা যাক ...", এটি কোড পর্যালোচনার জন্য অনুরোধ নয়, তবে সাধারণ প্রোগ্রামিং নীতি সম্পর্কে একটি প্রশ্ন।
200_সুসেস

@ 200_success আপনাকে ধন্যবাদ, এবং দুঃখিত, আমি এই সি আর জন্য পর্যাপ্ত হবে
গোগ্রাসে গেলা


2
ভবিষ্যতে আপনি ভবিষ্যতের অনুরূপ প্রশ্নের তুলনায় ফ্ল্যাফির পরিবর্তে "উইজেট" দিয়ে আরও ভাল থাকবেন, যেমন কোনও উইজেট উদাহরণগুলির পক্ষে একটি বিশেষ-অবস্থান হিসাবে বিবেচিত হয়।
মিনিটে হোসনেম দিন

1
আমি জানি এটি কেবল উদাহরণ কোড, তবে DateTime.UtcNowআপনি দিবালোক সঞ্চয় পরিবর্তনগুলি, বা বর্তমান সময়ের অঞ্চল পরিবর্তন এমনকি এড়িয়ে চলুন।
মার্ক হার্ট

উত্তর:


23

এই শ্রেণিটি যদি সত্যিই তুচ্ছ মনে হয় তবে এটি এসআরপি লঙ্ঘন করার বিষয়ে চিন্তা করার দরকার পড়েনি। সুতরাং যদি 3-লাইন ফাংশনটিতে 2 টি লাইন একটি জিনিস করে এবং অন্য 1 লাইন অন্য কিছু করে? হ্যাঁ, এই তুচ্ছ কাজটি এসআরপি লঙ্ঘন করে এবং তাই কি? কে পাত্তা দেয়? যখন জিনিসগুলি আরও জটিল হয় তখন এসআরপি লঙ্ঘন একটি সমস্যা হতে শুরু করে।

এই বিশেষ ক্ষেত্রে আপনার সমস্যা সম্ভবত এই কারণ থেকে উদ্ভূত হয়েছে যে ক্লাসটি আপনি আমাদের দেখিয়েছেন এমন কয়েকটি লাইনের চেয়ে জটিল is

বিশেষত, সমস্যাটি সম্ভবত সম্ভবত এই অবস্থাতেই থাকে যে এই শ্রেণিটি কেবল ক্যাশে পরিচালনা করে না, তবে সম্ভবত GetFluffiesFromDb()পদ্ধতিটির বাস্তবায়নও অন্তর্ভুক্ত করে । সুতরাং, এসআরপি লঙ্ঘন ক্লাসে রয়েছে, আপনার পোস্ট করা কোডটিতে প্রদর্শিত কয়েকটি তুচ্ছ পদ্ধতিতে নয়।

সুতরাং, সাজসজ্জার প্যাটার্নের সহায়তায়, এই সাধারণ বিভাগের মধ্যে আসা সমস্ত ধরণের কেসগুলি কীভাবে পরিচালনা করবেন সে সম্পর্কে এখানে একটি পরামর্শ ।

/// Provides Fluffies.
interface FluffiesProvider
{
    Fluffies GetFluffies();
}

/// Implements FluffiesProvider using a database.
class DatabaseFluffiesProvider : FluffiesProvider
{
    public override Fluffies GetFluffies()
    {
        ... load fluffies from DB ...
        (the entire implementation of "GetFluffiesFromDb()" goes here.)
    }
}

/// Decorates FluffiesProvider to add caching.
class CachingFluffiesProvider : FluffiesProvider
{
    private FluffiesProvider decoree;
    private DateTime m_NextReload = DateTime.MinValue;
    private Fluffies m_Cache;

    public CachingFluffiesProvider( FluffiesProvider decoree )
    {
        Assert( decoree != null );
        this.decoree = decoree;
    }

    public override Fluffies GetFluffies()
    {
        if( DateTime.Now >= m_NextReload ) 
        {
             m_Cache = decoree.GetFluffies();
             m_NextReload = DatTime.Now + TimeSpan.FromHours(1);
        }
        return m_Cache;
    }
}

এবং এটি নিম্নলিখিত হিসাবে ব্যবহৃত হয়:

FluffiesProvider provider = new DatabaseFluffiesProvider();
provider = new CachingFluffiesProvider( provider );
...go ahead and use provider...

নোট কীভাবে CachingFluffiesProvider.GetFluffies()কোডটি ধারণ করতে ভয় পাচ্ছে না যা সময় পরীক্ষা এবং আপডেট করার সময় করে, কারণ এটি তুচ্ছ জিনিস। এই প্রক্রিয়াটি যা করে তা হ'ল সিস্টেম ডিজাইন স্তরে এসআরপিকে সম্বোধন করা এবং পরিচালনা করা, যেখানে এটি গুরুত্বপূর্ণ, ক্ষুদ্র স্বতন্ত্র পদ্ধতিগুলির স্তরে নয়, যেখানে এটি কোনওভাবেই আসে না।


1
ফ্লাফি, ক্যাশিং এবং ডেটা বেস অ্যাক্সেসকে স্বীকৃতি দেওয়ার জন্য +1 আসলে তিনটি দায়িত্ব। এমনকি আপনি ফ্লাফিপ্রভাইডার ইন্টারফেস এবং ডেকোরেটরদের জেনেরিক (আইপ্রোভাইডার <ফ্লুফি>, ...) বানানোর চেষ্টা করতে পারেন তবে এটি YAGNI হতে পারে।
রোমান রেইনার

সত্যিই, যদি কেবলমাত্র এক ধরণের ক্যাশে থাকে এবং এটি সর্বদা ডাটাবেস থেকে বস্তুগুলি টানতে থাকে, এটি আইএমএইচও হ'ল ভারীভাবে ছাড়িয়ে যায় (যদিও "প্রকৃত" শ্রেণি আরও উদাহরণস্বরূপ আমরা দেখতে পাচ্ছি তাই জটিল)। বিমূর্ততা কেবল বিমূর্ততার খাতিরে কোড ক্লিনার বা আরও রক্ষণাবেক্ষণযোগ্য করে না।
ডক ব্রাউন

@ ডকব্রাউন সমস্যা হ'ল প্রশ্নের প্রসঙ্গের অভাব। আমি এই উত্তরটি পছন্দ করেছিলাম এটি একটি উপায় দেখায় যা আমি বৃহত্তর অ্যাপ্লিকেশনগুলিতে পুনরায় সময় এবং সময় ব্যবহার করেছি এবং এর বিরুদ্ধে পরীক্ষাগুলি লিখতে সহজ, আমি আমার উত্তরটিও পছন্দ করি কারণ এটি কেবলমাত্র একটি ছোট পরিবর্তন এবং কোনও অতিরিক্ত ছাড়পত্র ছাড়াই পরিষ্কার কিছু পাওয়া যায় বর্তমানে দাঁড়িয়েছে, প্রসঙ্গ ছাড়া প্রায় কাছাকাছি এখানে সব উত্তর ভালো:]
stijn

1
এফডব্লিউআইডাব্লু, প্রশ্নটি জিজ্ঞাসা করার সময় আমি যে ক্লাসটি মনে রেখেছিলাম তা ফ্লফি ম্যানেজারের চেয়ে জটিল, তবে অতিরিক্তভাবে নয়। প্রায় 200 লাইন, সম্ভবত। আমি এই প্রশ্নটি জিজ্ঞাসা করিনি কারণ আমি আমার ডিজাইনের (এখনও?) কোনও সমস্যা পেয়েছি, কেবল এসআরপি’র সাথে কঠোরভাবে মেনে চলার উপায় খুঁজে পাচ্ছি না, এবং এটি আরও জটিল ক্ষেত্রে সমস্যা হতে পারে। সুতরাং, প্রসঙ্গে অভাব কিছুটা উদ্দেশ্যযুক্ত। আমি মনে করি এই উত্তরটি দুর্দান্ত।
গোগ্রাসে গেলা

2
@ স্টিজন: ভাল, আমি মনে করি আপনার উত্তরটি ভারী মূল্যহীন is অপ্রয়োজনীয় বিমূর্ততা যোগ করার পরিবর্তে, আপনি কেবল আলাদা আলাদাভাবে দায়িত্বগুলি কেটে রাখুন এবং নাম দিন, যা এজাতীয় সমস্যার জন্য উত্তরাধিকারের তিন স্তরকে পাইল করার আগে সর্বদা প্রথম পছন্দ হওয়া উচিত।
ডক ব্রাউন

6

আপনার ক্লাসটি নিজেই আমার কাছে ভাল লাগছে তবে আপনি LoadFluffies()ঠিক ঠিক নামটির বিজ্ঞাপন হিসাবে প্রচার করেন না। একটি সহজ সমাধান হ'ল নাম পরিবর্তন করা এবং গেটফ্লুফিজের বাইরে স্পষ্টভাবে পুনরায় লোড করা, একটি উপযুক্ত বর্ণনা সহ একটি ফাংশনে। কিছুটা এইরকম

public Fluffies GetFluffies()
{
  MakeSureTheFluffyCacheIsUpToDate();
  return m_Cache;
}

private void MakeSureTheFluffyCacheIsUpToDate()
{
  if( !NeedsReload )
    return;
  GetFluffiesFromDb();
  SetNextReloadTime();
}

আমার কাছে পরিষ্কার দেখাচ্ছে (কারণ যেমন প্যাট্রিক বলেছেন: এটি অন্যান্য ক্ষুদ্র এসআরপি-আনুগত্যমূলক ফাংশনগুলি নিয়ে গঠিত) এবং বিশেষত এটি পরিষ্কারও রয়েছে যা কখনও কখনও ততটা গুরুত্বপূর্ণ।


1
আমি এর সরলতা পছন্দ।
গোগ্রাসে গেলা

6

আমি বিশ্বাস করি আপনার ক্লাস একটি কাজ করছে; এটি একটি সময়সীমা সহ ডেটা ক্যাশে। আপনি একাধিক জায়গা থেকে কল না করলে লোডফ্ল্যাফিজগুলি একটি অকেজো বিমূর্ততা বলে মনে হয়। আমি মনে করি লোডফ্লুফিজ থেকে দুটি লাইন নেওয়া এবং এটিকে getFluffies- এ নিডসেলোড শর্তাধীন রাখতে আরও ভাল হবে। এটি গেটফ্লফিজের বাস্তবায়নকে আরও অনেক সুস্পষ্ট করে তুলবে এবং এটি এখনও পরিষ্কার কোড, আপনি একক লক্ষ্য অর্জনের জন্য একক দায়িত্ব সাবরুটাইনগুলি রচনা করছেন, ডিবি থেকে ডেটা ক্যাশেড পুনরুদ্ধার। নীচে আপডেট গেট ফ্লাফিজ পদ্ধতিটি রয়েছে।

public Fluffies GetFluffies()
{
    if (NeedsReload()) {
        GetFluffiesFromDb();
        UpdateNextLoad();
    }

    return m_Cache;
}

যদিও এটি বেশ ভাল প্রথম উত্তর, তবে দয়া করে মনে রাখবেন যে "ফলাফল" কোডটি প্রায়শই একটি ভাল সংযোজন।
মনিকার লসুইট ফান্ড করুন

4

আপনার প্রবৃত্তি সঠিক। আপনার ক্লাসটি ছোট হলেও এটি খুব বেশি করছে। আপনার টাইমড রিফ্রেশ ক্যাচিং লজিককে সম্পূর্ণ জেনেরিক শ্রেণিতে আলাদা করা উচিত। তারপরে ফ্লাফিগুলি পরিচালনার জন্য সেই শ্রেণীর একটি নির্দিষ্ট উদাহরণ তৈরি করুন, এর মতো কিছু (সংকলিত নয়, কার্য কোড পাঠকের জন্য অনুশীলন হিসাবে রেখে দেওয়া হয়েছে):

public class TimedRefreshCache<T> {
    T m_Value;
    DateTime m_NextLoadTime;
    Func<T> m_producer();
    public CacheManager(Func<T> T producer, Interval timeBetweenLoads) {
          m_nextLoadTime = INFINITE_PAST;
          m_producer = producer;
    }
    public T Value {
        get {
            if (m_NextLoadTime < DateTime.Now) {
                m_Value = m_Producer();
                m_NextLoadTime = ...;
            }
            return m_Value;
        }
    }
}

public class FluffyCache {
    private TimedRefreshCache m_Cache 
        = new TimedRefreshCache<Fluffy>(GetFluffiesFromDb, interval);
    private Fluffy GetFluffiesFromDb() { ... }
    public Fluffy Value { get { return m_Cache.Value; } }
}

একটি অতিরিক্ত সুবিধা হ'ল টাইমড্রেফ্রেশক্যাস পরীক্ষা করা এখন খুব সহজ।


1
আমি সম্মত হই যে উদাহরণের তুলনায় যদি রিফ্রেশ যুক্তি আরও জটিল হয়ে ওঠে তবে এটিকে পৃথক শ্রেণিতে পরিণত করা ভাল ধারণা হতে পারে। তবে আমি একমত নই যে উদাহরণে ক্লাসটি যেমন হয় তেমন অনেক কিছু করে।
ডক ব্রাউন

@ কেভিন, আমি টিডিডিতে অভিজ্ঞ নই। আপনি কীভাবে টাইমড্রাফ্রেসক্যাচ পরীক্ষা করবেন তা বিশদভাবে জানাতে পারেন? আমি এটিকে "খুব সহজ" হিসাবে দেখছি না, তবে এটি আমার দক্ষতার অভাব হতে পারে।
গোগ্রাসে গেলা

1
আপনার উত্তরটি জটিলতার কারণে আমি ব্যক্তিগতভাবে পছন্দ করি না। এটি খুব সাধারণ এবং খুব বিমূর্ত এবং আরও জটিল পরিস্থিতিতে সেরা হতে পারে। তবে এই সাধারণ ক্ষেত্রে এটি 'কেবলমাত্র অনেক কিছু'। অনুগ্রহ করে জবাবদিহি করুন কি সুন্দর, সংক্ষিপ্ত এবং পাঠযোগ্য উত্তর। প্রত্যেকে এটি লক্ষ্য করে বুঝতে পারবে। আপনি কি মনে করেন?
ডিয়েটার মীমকেন

1
@ রেভেন আপনি সংক্ষিপ্ত বিরতি (100 মিমি) এবং খুব সাধারণ নির্মাতাকে (ডেটটাইম.নো এর মতো) ব্যবহার করে টাইমড্রিফ্রেসক্যাচ পরীক্ষা করতে পারেন। প্রতি 100 এমএসে ক্যাশে একটি নতুন মান উত্পন্ন করবে, এর মধ্যে পূর্ববর্তী মানটি ফিরিয়ে দেবে।
কেভিন

1
@ ডকব্রাউন: সমস্যাটি হ'ল লিখিতভাবে এটি অবিশ্বাস্য। সময় যুক্তি (পরীক্ষণযোগ্য) ডাটাবেস যুক্তির সাথে মিলিত হয়, যা পরে তামাশা করা হয়। একবার ডেটাবেস কলকে উপহাস করার জন্য কোনও সিম তৈরি হয়ে গেলে, আপনি জেনেরিক সমাধানের 95% পথ। আমি দেখেছি যে এই ছোট্ট ক্লাসগুলি তৈরি করা সাধারণত পরিশোধ করে দেয় কারণ তারা প্রত্যাশার চেয়ে বেশি পুনরায় ব্যবহার করা শেষ করে।
কেভিন

1

আপনার ক্লাসটি ঠিক আছে, এসআরপি কোনও শ্রেণি সম্পর্কে কোনও ফাংশন নয়, পুরো ক্লাসটি "ডেটা উত্স" থেকে "ফ্লফিগুলি" সরবরাহ করার জন্য দায়বদ্ধ যাতে আপনি অভ্যন্তরীণ বাস্তবায়নে মুক্ত হন।

আপনি যদি কাহিং প্রক্রিয়াটি প্রসারিত করতে চান তবে ডেটা উত্স দেখার জন্য আপনি শ্রেনী বর্গ তৈরি করতে পারেন

public class ModelWatcher
{

    private static Dictionary<Type, DateTime> LastUpdate;

    public static bool IsUpToDate(Type entityType, DateTime lastRead) {
        if (LastUpdate.ContainsKey(entityType)) {
            return lastRead >= LastUpdate[entityType];
        }
        return true;
    }

    //call this method whenever insert/update changed to any entity
    private void OnDataSourceChanged(Type changedEntityType) {
        //update Date & Time
        LastUpdate[changedEntityType] = DateTime.Now;
    }
}
public class FluffyManager
{
    private DateTime LastRead = DateTime.MinValue;

    private List<Fluffy> list;



    public List<Fluffy> GetFluffies() {

        //if first read or not uptodated
        if (list==null || !ModelWatcher.IsUpToDate(typeof(Fluffy),LastRead)) {
            list = ReadFluffies();
        }
        return list;
    }
    private List<Fluffy> ReadFluffies() { 
    //read code
    }
}

চাচা ববের মতে: ফাংশনগুলি এক জিনিস করা উচিত। তারা এটি করতে হবে। তারা কেবল এটি করা উচিত। সাফ কোড পি .35।
গোগ্রাসে গেলা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.