একক দায়িত্ব এবং কাস্টম ডেটা প্রকার


10

বিগত মাসগুলিতে আমি এখানে এসई এবং অন্যান্য সাইটে লোকদের কাছে জিজ্ঞাসা করেছি আমার কোড সম্পর্কে কিছু গঠনমূলক সমালোচনা offer একটি জিনিস রয়েছে যা প্রায় প্রতিবারই পপ আউট করে চলেছে এবং আমি এখনও সেই প্রস্তাবের সাথে একমত নই; : পি আমি এখানে এটি নিয়ে আলোচনা করতে চাই এবং সম্ভবত বিষয়গুলি আমার কাছে পরিষ্কার হয়ে যাবে।

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

মাই ফন্ট ক্লাস থেকে একটি টুকরা

class Font
{
  public:
    bool isLoaded() const;
    void loadFromFile(const std::string& file);
    void loadFromMemory(const void* buffer, std::size_t size);
    void free();

    void some();
    void another();
};

প্রস্তাবিত নকশা

class Font
{
  public:
    void some();
    void another();
};


class FontFactory
{
  public:
    virtual std::unique_ptr<Font> createFromFile(...) = 0;
    virtual std::unique_ptr<Font> createFromMemory(...) = 0;
};

প্রস্তাবিত নকশাটি অনুমিতভাবে এসআরপি অনুসরণ করে, তবে আমি একমত নই - আমার মনে হয় এটি খুব বেশি এগিয়ে গেছে। Fontশ্রেণী আর স্বাবলম্বী (এটা কারখানা ছাড়া অনর্থক), এবং নয় FontFactoryচাহিদা রিসোর্স, যা সম্ভবত বন্ধুত্ব বা পাবলিক getters মাধ্যমে সম্পন্ন করা হয় বাস্তবায়ন, যা আরো বাস্তবায়ন এক্সপোজ সম্পর্কে বিস্তারিত জানতে Font। আমি মনে করি এটি বরং খণ্ডিত দায়বদ্ধতার একটি মামলা ।

আমার দৃষ্টিভঙ্গি আরও ভাল বলে আমি এখানে কেন মনে করি:

  • Fontস্বাবলম্বী - স্বাবলম্বী হওয়া, এটি বোঝা এবং বজায় রাখা আরও সহজ। এছাড়াও, আপনি অন্য কিছু অন্তর্ভুক্ত না করে ক্লাসটি ব্যবহার করতে পারেন। তবে, যদি আপনি খুঁজে পান যে আপনার আরও জটিল সংস্থান প্রয়োজন (একটি কারখানা) আপনার এটি খুব সহজেই করতে পারেন (পরে আমি আমার নিজস্ব কারখানা সম্পর্কে কথা বলব, ResourceManager<Font>)।

  • স্ট্যান্ডার্ড লাইব্রেরি অনুসরণ করে - আমি বিশ্বাস করি যে ব্যবহারকারী-সংজ্ঞায়িত প্রকারগুলি সেই সংশ্লিষ্ট ভাষায় মানক প্রকারের আচরণটি অনুলিপি করার জন্য যথাসম্ভব চেষ্টা করা উচিত। std::fstreamস্বাবলম্বী হয় এবং এটি মতো কাজগুলির প্রদান করে openএবং close। স্ট্যান্ডার্ড লাইব্রেরি অনুসরণ করার অর্থ জিনিসগুলি করার আরও একটি উপায় শেখার জন্য প্রচেষ্টা ব্যয় করার দরকার নেই। এ ছাড়া, সাধারণভাবে বলতে গেলে, সি ++ স্ট্যান্ডার্ড কমিটি সম্ভবত এখানে কারও চেয়ে নকশা সম্পর্কে আরও বেশি জানেন, তাই যদি সন্দেহ হয় তবে তারা যা করেন তা অনুলিপি করুন।

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

  • এটি প্রাসঙ্গিক অজ্ঞেয়বাদী - (এটি আমার প্রথম পয়েন্টটির সাথে কিছুটা ছেদ Fontকরে ) ব্যবহারকারীকে কারখানা ব্যবহার করতে বাধ্য করা ক্লাসগুলির মধ্যে সংযোগ বাড়িয়ে তোলে।

আমারও একটা কারখানা আছে

(কারণ ডিজাইনটি Fontআমাকে অনুমতি দেয়))

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

template<class T>
class ResourceManager
{
  public:
    ResourcePtr<T> acquire(const std::string& file);
    ResourcePtr<T> acquire(const void* buffer, std::size_t size);
};

ম্যানেজারটি কীভাবে ব্যবহার করা যেতে পারে তার একটি প্রদর্শন এখানে's লক্ষ্য করুন যে এটি কারখানার মত মূলত ব্যবহৃত হয়েছিল।

void test(ResourceManager<Font>* rm)
{
    // The same file isn't loaded twice into memory.
    // I can still have as many Fonts using that file as I want, though.
    ResourcePtr<Font> font1 = rm->acquire("fonts/arial.ttf");
    ResourcePtr<Font> font2 = rm->acquire("fonts/arial.ttf");

    // Print something with the two fonts...
}

শেষের সারি...

(এটি এখানে একটি টিএল লাগাতে চাই; ড।, তবে আমি একটির কথা ভাবতে পারি না::
there ) ঠিক আছে, আপনি এখানে আছেন, আমি আমার কেসটি যথাসম্ভব সেরা করে তুলেছি। আপনার যে কোনও পাল্টা যুক্তি যুক্ত করুন এবং প্রস্তাবিত ডিজাইনটি আমার নিজের ডিজাইনের উপরে রয়েছে বলে মনে করেন এমন কোনও সুবিধা পোস্ট করুন। মূলত, আমাকে ভুল দেখানোর চেষ্টা করুন I'm :)


2
আমাকে মার্টিন ফোলারের অ্যাক্টিভেকর্ড বনাম ডেটা ম্যাপার স্মরণ করিয়ে দেয় ।
ব্যবহারকারী

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


@Rwong আমি এই উপস্থাপনাটি সম্পর্কে জানি, এটিতে আমার একটি বুকমার্ক ছিল ( ভিডিও )। :) তবে আপনি নিজের অন্যান্য মন্তব্যে কী বলছেন তা আমি বুঝতে পারি না ...
পল

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

উত্তর:


7

আমার মতে এই কোডটির সাথে কোনও ভুল নেই, এটি আপনার বোধগম্য এবং যুক্তিযুক্তভাবে সহজ পদ্ধতিতে বজায় রাখা দরকার তা করে does

তবে এই কোডটি নিয়ে আপনার যে সমস্যাটি রয়েছে তা হ'ল আপনি যদি এটি অন্য কিছু করতে চান তবে আপনাকে এটি সব পরিবর্তন করতে হবে

এসআরপির মূল বিষয়টি হ'ল যদি আপনার কাছে একটি একক উপাদান 'কমপ্যাক' থাকে যা অ্যালগোরিদম এ () করে এবং আপনার অ্যালগোরিদম এ () পরিবর্তন করতে হবে তবে আপনারও 'কমপাব' পরিবর্তন করতে হবে না।

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

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


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

হ্যাঁ, যেমনটি আমি বলেছিলাম, আমার সি ++ দক্ষতাগুলি বেশ মরিচাটে তাই আমি সমস্যার একটি বাস্তব প্রদর্শনী নিয়ে আসতে সংগ্রাম করেছি, নমনীয়তার বিষয়ে আমি সম্মত। এটি আপনার কোড সহ আপনি যা যাচ্ছেন তা সত্যিই নির্ভর করে, যেমন আমি বলেছিলাম, আমি মনে করি আপনার মূল কোডটি সমস্যার যথাযথভাবে যুক্তিযুক্ত সমাধান is
এড জেমস

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

0

আপনার ক্লাস সম্পর্কে আমাকে যা বাগিয়ে দেয় তা হ'ল আপনার loadFromMemoryএবং loadFromFileপদ্ধতিগুলি। আদর্শভাবে, আপনার কেবল loadFromMemoryপদ্ধতি থাকা উচিত ; একটি ফন্টে মেমরির ডেটা কীভাবে এসেছিল সেদিকে নজর দেওয়া উচিত নয়। আরেকটি বিষয় হ'ল আপনার লোড এবং freeপদ্ধতির পরিবর্তে কনস্ট্রাক্টর / ডেস্ট্রাক্টর ব্যবহার করা উচিত । সুতরাং, loadFromMemoryহয়ে উঠবে Font(const void *buf, int len)এবং free()হয়ে যাবে ~Font()


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