হিসাবে বেশ কিছু উত্তর এবং মন্তব্য বলেছেন, DTOs হয় বিশেষত গণ্ডি জুড়ে ডেটা ট্রান্সফারের (যেমন তাদেরকে JSON করার serializing একটি ওয়েব পরিষেবা মাধ্যমে পাঠাতে করার জন্য), কিছু পরিস্থিতিতে উপযুক্ত এবং দরকারী। এই উত্তরের বাকী অংশের জন্য, আমি কম-বেশি সেটিকে উপেক্ষা করব এবং ডোমেন ক্লাস সম্পর্কে কথা বলব এবং কীভাবে তারা গ্রিডার এবং সেটটারগুলি কমিয়ে আনতে (যদি নির্মূল না করা হয়) ডিজাইন করা যায় এবং এখনও একটি বড় প্রকল্পে কার্যকর হতে পারে। আমি কেন গেটার বা সেটটারগুলি সরান, বা কখন এটি করব সে সম্পর্কে কথা বলব না , কারণ সেগুলি তাদের নিজস্ব প্রশ্ন।
উদাহরণ হিসাবে, কল্পনা করুন যে আপনার প্রকল্পটি দাবা বা যুদ্ধের মতো একটি বোর্ড গেম game আপনার উপস্থাপনা স্তরে এটি উপস্থাপনের বিভিন্ন উপায় থাকতে পারে (কনসোল অ্যাপ্লিকেশন, ওয়েব পরিষেবা, জিইউআই, ইত্যাদি), তবে আপনার একটি মূল ডোমেনও রয়েছে। আপনার কাছে থাকতে পারে একটি বর্গ হ'ল Coordinate
বোর্ডে একটি অবস্থান উপস্থাপন করে। এটি লেখার "দুষ্ট" উপায়টি হ'ল:
public class Coordinate
{
public int X {get; set;}
public int Y {get; set;}
}
(আমি জাভাের পরিবর্তে সি # তে কোড উদাহরণ লিখতে যাচ্ছি, ব্রিভিটির জন্য এবং কারণ এটির সাথে আমি আরও বেশি পরিচিত Hope আশা করি এটি কোনও সমস্যা নয় The ধারণাটি একই রকম এবং অনুবাদটি সহজ হওয়া উচিত))
সেটারগুলি অপসারণ: অপরিবর্তনীয়তা
যদিও পাবলিক গেটার্স এবং সেটারগুলি উভয়ই সম্ভাব্য সমস্যাযুক্ত, সেটারগুলি উভয়েরই বেশি "দুষ্ট"। এগুলি সাধারণত মুছে ফেলা সহজ। প্রক্রিয়াটি একটি সাধারণ এক - নির্ধারকের মধ্য থেকে মান নির্ধারণ করে। কোনও পদ্ধতি যা পূর্বে বস্তুকে রূপান্তরিত করেছিল তার পরিবর্তে একটি নতুন ফলাফল ফিরিয়ে আনতে হবে। তাই:
public class Coordinate
{
public int X {get; private set;}
public int Y {get; private set;}
public Coordinate(int x, int y)
{
X = x;
Y = y;
}
}
নোট করুন যে এটি X এবং Y শ্রেণীর পরিবর্তিত শ্রেণীর অন্যান্য পদ্ধতির বিরুদ্ধে সুরক্ষা দেয় না more আরও কঠোরভাবে অপরিবর্তনীয় হওয়ার জন্য, আপনি readonly
( final
জাভাতে) ব্যবহার করতে পারেন । তবে যেভাবেই হোক- আপনি আপনার সম্পত্তিগুলি সত্যিকারের অপরিবর্তনীয় করে তুলুন বা কেবল সেটারগুলির মাধ্যমে সরাসরি জনসাধারণের বিবর্তন রোধ করুন- এটি আপনার সর্বজনীন সেটটারগুলি সরানোর কৌশল করে। বেশিরভাগ পরিস্থিতিতে, এটি ঠিক কাজ করে।
গেটারগুলি সরানো, পর্ব 1: আচরণের জন্য ডিজাইন করা
উপরোক্ত সমস্ত সেটারদের জন্য ভাল এবং ভাল, তবে গেটারদের ক্ষেত্রে, আমরা এমনকি শুরু করার আগে পায়ের কাছে নিজেকে গুলি করেছিলাম। আমাদের প্রক্রিয়াটি একটি স্থানাঙ্ক কী তা- এটি যে ডেটা উপস্থাপন করে তা ভাবতে হয়েছিল - এবং তার চারপাশে একটি শ্রেণি তৈরি করে। পরিবর্তে, একটি সমন্বয় থেকে আমাদের কী আচরণ প্রয়োজন তা দিয়ে আমাদের শুরু করা উচিত ছিল । এই প্রক্রিয়াটি, যাইহোক, টিডিডি দ্বারা সাহায্যপ্রাপ্ত, যেখানে আমাদের কেবল একবার প্রয়োজন পড়ার পরে আমরা এই জাতীয় ক্লাসগুলি বের করি, তাই আমরা সেগুলি থেকে কাঙ্ক্ষিত আচরণ এবং কাজ শুরু করি।
সুতরাং আসুন আমরা বলি যে আপনি যে প্রথমে নিজেকে খুঁজে পেয়েছিলেন Coordinate
তা সংঘর্ষ শনাক্তকরণের জন্য ছিল: আপনি বোর্ডে দুটি টুকরা একই জায়গা দখল করেছেন কিনা তা পরীক্ষা করে দেখতে চেয়েছিলেন। এখানে "দুষ্টু" উপায় (নির্মাতারা বংশবৃদ্ধির জন্য বাদ দেওয়া হয়েছে):
public class Piece
{
public Coordinate Position {get; private set;}
}
public class Coordinate
{
public int X {get; private set;}
public int Y {get; private set;}
}
//...And then, inside some class
public bool DoPiecesCollide(Piece one, Piece two)
{
return one.X == two.X && one.Y == two.Y;
}
এবং এখানে ভাল উপায়:
public class Piece
{
private Coordinate _position;
public bool CollidesWith(Piece other)
{
return _position.Equals(other._position);
}
}
public class Coordinate
{
private readonly int _x;
private readonly int _y;
public bool Equals(Coordinate other)
{
return _x == other._x && _y == other._y;
}
}
( IEquatable
বাস্তবায়ন সংক্ষিপ্তসার জন্য সংক্ষিপ্ত)। ডেটা মডেলিংয়ের পরিবর্তে আচরণের জন্য ডিজাইনিং করে, আমরা আমাদের গেটারগুলি সরাতে সক্ষম হয়েছি।
নোট করুন এটি আপনার উদাহরণের সাথেও প্রাসঙ্গিক। আপনি কোনও ওআরএম ব্যবহার করছেন, বা কোনও ওয়েবসাইট বা অন্য কোনও ক্ষেত্রে গ্রাহকের তথ্য প্রদর্শন করছেন, Customer
এক্ষেত্রে কোনও ধরণের ডিটিও সম্ভবত বোধগম্য হবে। তবে কেবলমাত্র আপনার সিস্টেমে গ্রাহকরা রয়েছে এবং সেগুলি ডেটা মডেলটিতে প্রতিনিধিত্ব করা হয়েছে তা স্বয়ংক্রিয়ভাবে এর অর্থ এই নয় যে Customer
আপনার ডোমেনে আপনার ক্লাস থাকা উচিত । আচরণের জন্য আপনি যেমন নকশা তৈরি করেছেন তেমন একটি আবির্ভূত হবে তবে আপনি যদি গেটারদের এড়াতে চান তবে প্রাক-উদ্বেগজনকভাবে একটি তৈরি করবেন না।
গেটারগুলি সরানো, পর্ব 2: বাহ্যিক আচরণ
তাই উপরে একটি ভালো শুরু, কিন্তু কখনো কখনো আপনি সম্ভবত একটি অবস্থা যেখানে আপনি আচরণ যা বর্গ, যা কোনো না কোনোভাবে শ্রেণী রাষ্ট্রীয় উপর নির্ভর করে সঙ্গে যুক্ত করা হয় আছে মধ্যে চালানো হবে, কিন্তু যা অন্তর্গত নয় উপর বর্গ। এই ধরণের আচরণটি সাধারণত আপনার আবেদনের পরিষেবা স্তরে থাকে ।
আমাদের Coordinate
উদাহরণটি গ্রহণ করে , অবশেষে আপনি আপনার গেমটি ব্যবহারকারীর কাছে উপস্থাপন করতে চাইবেন এবং এর অর্থ স্ক্রিনে আঁকা। উদাহরণস্বরূপ, আপনার কাছে একটি ইউআই প্রকল্প থাকতে পারে যা Vector2
স্ক্রিনের একটি পয়েন্ট উপস্থাপন করতে ব্যবহার করে। তবে Coordinate
ক্লাসের পক্ষে স্ক্রিনের একটি স্থানাঙ্ক থেকে কোনও বিন্দুতে রূপান্তর করার দায় গ্রহণ করা অনুচিত হবে-যা আপনার মূল ডোমেনে সমস্ত প্রকার উপস্থাপনা উদ্বেগ নিয়ে আসবে। দুর্ভাগ্যক্রমে এই ধরণের পরিস্থিতি ওও ডিজাইনের অন্তর্নিহিত।
প্রথম বিকল্পটি , যা খুব সাধারণভাবে বেছে নেওয়া হয়, তা হ'ল অভিশাপদাতাদের উন্মোচন করা এবং এটি দিয়ে জাহান্নামে বলতে। এটি সরলতার সুবিধা আছে। তবে যেহেতু আমরা গেটারদের এড়ানো সম্পর্কে কথা বলছি, আসুন তর্কের পক্ষে বলি আমরা এটিকে প্রত্যাখ্যান করি এবং অন্যান্য বিকল্পগুলি কী রয়েছে তা দেখুন।
দ্বিতীয় বিকল্পটি হ'ল .ToDTO()
আপনার ক্লাসে কিছু ধরণের পদ্ধতি যুক্ত করা। এটি- বা অনুরূপ- যাইহোক ভালভাবে প্রয়োজন হতে পারে, উদাহরণস্বরূপ আপনি যখন গেমটি সংরক্ষণ করতে চান তখন আপনাকে আপনার রাজ্যের বেশিরভাগ অংশ ক্যাপচার করতে হবে। তবে আপনার পরিষেবাদিগুলির জন্য এটি করার এবং সরাসরি গিটারের সরাসরি অ্যাক্সেসের মধ্যে পার্থক্য কম বেশি নান্দনিক। এটি এখনও এটির যতটা "মন্দ" রয়েছে।
তৃতীয় বিকল্প - যা আমি জোড়ান হরভাত দ্বারা বেশ কয়েকটি বহুবচন ভিডিওতে সমর্থন করে দেখেছি - সেটি হল দর্শকের ধরণটির পরিবর্তিত সংস্করণ ব্যবহার করা use এটি একটি নিখুঁত অস্বাভাবিক ব্যবহার এবং প্যাটার্নের প্রকরণ এবং আমি মনে করি যে জনগণের মাইলেজ এটি বাস্তব লাভের জন্য জটিলতা যুক্ত করছে না বা পরিস্থিতিটির জন্য এটি একটি সুন্দর সমঝোতা কিনা on ধারণাটি মূলত স্ট্যান্ডার্ড ভিজিটর প্যাটার্নটি ব্যবহার করার জন্য, তবে যে Visit
পদ্ধতিতে তারা যাচ্ছেন তারা তার ক্লাসের পরিবর্তে প্যারামিটার হিসাবে প্রয়োজনীয় রাষ্ট্রগুলি গ্রহণ করবেন। উদাহরণ এখানে পাওয়া যাবে ।
আমাদের সমস্যার জন্য, এই প্যাটার্নটি ব্যবহার করে সমাধানটি হ'ল:
public class Coordinate
{
private readonly int _x;
private readonly int _y;
public T Transform<T>(IPositionTransformer<T> transformer)
{
return transformer.Transform(_x,_y);
}
}
public interface IPositionTransformer<T>
{
T Transform(int x, int y);
}
//This one lives in the presentation layer
public class CoordinateToVectorTransformer : IPositionTransformer<Vector2>
{
private readonly float _tileWidth;
private readonly float _tileHeight;
private readonly Vector2 _topLeft;
Vector2 Transform(int x, int y)
{
return _topLeft + new Vector2(_tileWidth*x + _tileHeight*y);
}
}
আপনি সম্ভবত বলতে পারেন, _x
এবং সত্যিই আর কোনও encapsulated _y
হয় না । আমরা তাদের তৈরি করতে পারতাম এমন একটি তৈরি করে যা কেবল তাদের সরাসরি ফেরত দেয়। স্বাদের উপর নির্ভর করে আপনি অনুভব করতে পারেন এটি পুরো অনুশীলনকে অর্থহীন করে তুলেছে।IPositionTransformer<Tuple<int,int>>
যাইহোক, পাবলিক গেটসগুলির সাথে, জিনিসগুলি ভুল উপায়ে করা খুব সহজ, কেবল সরাসরি ডেটা টানতে এবং এটি বলুন, জিজ্ঞাসা করবেন না লঙ্ঘন করে । যদিও এই নিদর্শনটি ব্যবহার করে এটি সঠিক উপায়ে করা সহজতর : আপনি যখন আচরণ তৈরি করতে চান, আপনি স্বয়ংক্রিয়ভাবে এর সাথে সম্পর্কিত কোনও প্রকার তৈরি করে শুরু করবেন। টিডিএর লঙ্ঘন খুব স্পষ্টতই দুর্গন্ধযুক্ত হবে এবং সম্ভবত একটি সহজ, আরও ভাল সমাধানের জন্য কাজ করা প্রয়োজন। বাস্তবে, এই পয়েন্টগুলি এটিকে সঠিকভাবে করা আরও সহজ করে তোলে, ওও, "দুষ্ট" উপায়ের চেয়ে পথিকরা উত্সাহিত করে।
পরিশেষে , এমনকি প্রাথমিকভাবে এটি সুস্পষ্ট না হলেও, বাস্তবে রাষ্ট্রকে প্রকাশের প্রয়োজন এড়াতে আপনার আচরণ হিসাবে প্রয়োজন যা যথেষ্ট তা প্রকাশ করার উপায় রয়েছে । উদাহরণস্বরূপ, Coordinate
যার পূর্ববর্তী সংস্করণটি কেবলমাত্র সর্বজনীন সদস্য হিসাবে ব্যবহার করা হয়েছে Equals()
(বাস্তবে এটির জন্য সম্পূর্ণ IEquatable
বাস্তবায়ন প্রয়োজন ) আপনি নিজের উপস্থাপনা স্তরে নিম্নলিখিত শ্রেণিটি লিখতে পারেন:
public class CoordinateToVectorTransformer
{
private Dictionary<Coordinate,Vector2> _coordinatePositions;
public CoordinateToVectorTransformer(int boardWidth, int boardHeight)
{
for(int x=0; x<boardWidth; x++)
{
for(int y=0; y<boardWidth; y++)
{
_coordinatePositions[new Coordinate(x,y)] = GetPosition(x,y);
}
}
}
private static Vector2 GetPosition(int x, int y)
{
//Some implementation goes here...
}
public Vector2 Transform(Coordinate coordinate)
{
return _coordinatePositions[coordinate];
}
}
এটি সক্রিয় আউট, সম্ভবত এটি আশ্চর্যজনক, সব আচরণ আমরা সত্যিই একটি থেকে প্রয়োজনীয় আমাদের লক্ষ্য সমতা পরীক্ষণ করা হয় অর্জন করা তুল্য! অবশ্যই, এই সমাধানটি এই সমস্যার জন্য উপযুক্ত, এবং গ্রহণযোগ্য মেমরির ব্যবহার / সম্পাদন সম্পর্কে অনুমান করে। এটি কেবলমাত্র একটি সাধারণ সমাধানের ব্লুপ্রিন্টের চেয়ে এই বিশেষ সমস্যা ডোমেনের সাথে ফিট করে।
এবং আবারও, বাস্তবে এটি অপ্রয়োজনীয় জটিলতা সম্পর্কে মতামতগুলি পৃথক হবে। কিছু ক্ষেত্রে, এর মতো কোনও সমাধানের অস্তিত্ব থাকতে পারে, বা এটি নিষিদ্ধভাবে অদ্ভুত বা জটিল হতে পারে, সেক্ষেত্রে আপনি উপরের তিনটিতে ফিরে যেতে পারেন।