Mastering Software Architecture සමඟ මෘදුකාංග ගෘහ නිර්මාණ ශිල්පයේ රහස් අගුළු හරින්න: 11 Key Design Patterns පැහැදිලි කර ඇත .
2. සැලසුම් රටාව - ඇඩප්ටරය
3. නිර්මාණ රටාව - ඉදි කරන්නා
4. වගකීම් දාමය භාවිතා කරන ආකාරය
5. මෝස්තර රටාව - සැරසිලිකරු
6. සැලසුම් රටාව - කර්මාන්තශාලා ක්රමය
7. සැලසුම් රටාව - පුනරාවර්තකය
8. නිර්මාණ රටාව - මැදිහත්කරු
9. නිර්මාණ රටාව - නිරීක්ෂකයා
10. අත්තිකාරම් දේපල රටාව C# 8.0
11. නිර්මාණ රටාව - සිංගල්ටන්
Gang of Four ට අනුව, කර්මාන්තශාලා නිර්මාණය කිරීමේ කර්මාන්තශාලාව ලෙස වියුක්ත කර්මාන්තශාලා රටා උපකල්පනය කළ හැකිය.
වියුක්ත කර්මාන්තශාලා රටාව තනිකරම දිගු කිරීමේ කර්මාන්තශාලා ක්රමයකි; වියුක්ත කර්මාන්තශාලා නිර්මාණය තේරුම් ගැනීමට පෙර කර්මාන්තශාලා ක්රමය හරහා යාම නිර්දේශ කෙරේ.
ඉතුරුම් සහ ජංගම ගිණුම් වැනි ගිණුම් වර්ග ඇති ඕනෑම බැංකුවක එකම උදාහරණය සලකා බලමු. දැන්, අපි ඉහත උදාහරණය වියුක්ත කර්මාන්තශාලා සැලසුම් රටාව භාවිතයෙන් ක්රියාත්මක කරමු.
පළමුව, ISavingAccount සහ ICurrentAccount අතුරුමුහුණත් පහත පරිදි ක්රියාත්මක කරන්න:
public interface ISavingAccount{ } public interface ICurrentAccount{ }
පහත පන්තිවල අතුරු මුහුණත උරුම කර ගන්න
public class CurrentAccount : ICurrentAccount { public CurrentAccount(string message) { Console.WriteLine(message); } } public class SavingsAccount : ISavingAccount { public SavingsAccount( string message) { Console.WriteLine(message); } }
එක් එක් ගිණුම් වර්ගය සඳහා වියුක්ත ක්රම සමඟ වියුක්ත පන්තියක් ලියමු.
public abstract class AccountTypeFactory { public abstract ISavingAccount SavingAccountFactory(string message); public abstract ICurrentAccount CurrentAccountFactory(string message); }
දැන්, වියුක්ත ක්රම ක්රියාත්මක කිරීම සපයන “Bank1Factory” නමින් කර්මාන්තශාලා ක්රියාත්මක කිරීමක් නිර්මාණය කරමු.
public class Bank1Factory : AccountTypeFactory { public override ICurrentAccount CurrentAccountFactory(string message) { return new CurrentAccount(message); } public override ISavingAccount SavingAccountFactory(string message) { return new SavingsAccount(message); } }
නිර්වචනයට අනුව කර්මාන්තශාලා ආපසු ලබා දෙන කර්මාන්තශාලා සැපයුම්කරුවෙකු ක්රියාත්මක කිරීමට අවශ්ය කර්මාන්තශාලා ක්රමයට වඩා වියුක්ත කර්මාන්තශාලා සැලසුම් රටාව වෙනස් වේ.
දැන් අපි සියලු වියුක්ත කිරීම් සහ කර්මාන්තශාලා නිර්මාණය කර ඇත. අපි කර්මාන්තශාලා සැපයුම්කරු නිර්මාණය කරමු. ස්ථිතික ක්රමයක් මඟින් ගිණුමේ නම මත පදනම්ව කර්මාන්තශාලාවක් සාදනු ලබන කර්මාන්තශාලා සැපයුම්කරු සඳහා වන කේත කොටස පහතින් සොයා ගන්න.
public class AccountFactoryProvider { public static AccountTypeFactory GetAccountTypeFactory(string accountName) { if (accountName.Contains("B1")) { return new Bank1Factory(); } else return null; } }
ගිණුමේ නමක් වචනාර්ථයෙන් “ B1 ” වලින් සමන්විත නම්, එය කර්මාන්තශාලා සැපයුම්කරු හරහා ආපසු ලබා දෙන Bank1Factory උදාහරණය භාවිතා කරන ගිණුම් අංක ලැයිස්තුවක් උදාහරණයක් ගනිමු.
static void Main(string[] args) { List<string> accNames = new List<string> { "B1-456", "B1-987", "B2-222" }; for (int i = 0; i < accNames.Count; i++) { AccountTypeFactory anAbstractFactory = AccountFactoryProvider.GetAccountTypeFactory(accNames[i]); if (anAbstractFactory == null) { Console.WriteLine("Invalid " + (accNames[i])); } else { ISavingAccount savingAccount = anAbstractFactory.SavingAccountFactory("Hello saving"); ICurrentAccount currentAccount = anAbstractFactory.CurrentAccountFactory("Hello Current"); } } Console.ReadLine(); }
ගිණුමේ නමෙහි “B1” වචනාර්ථය අඩංගු නොවේ නම්, වැඩසටහන අවලංගු {{accountName}} ප්රතිදානය කරයි
කරුණාකර ඉහත කේත කොටසේ ප්රතිදානය පහතින් සොයා ගන්න.
Hello saving B1-456 Hello Current B1-456 Hello saving B1-987 Hello Current B1-987
Gang of Four ට අනුව, Adapter Pattern මගින් class එකක අතුරුමුහුණත් සේවාදායකයාට අවශ්ය අතුරුමුහුණත් බවට පරිවර්තනය කරයි.
වෙනත් වචන වලින් කිවහොත්, ඇඩැප්ටර සැලසුම් රටාව නොගැලපෙන අතුරුමුහුණත් සාමූහිකව වැඩ කිරීමට උපකාරී වේ.
සංවිධාන දෙකක් ඒකාබද්ධ කිරීම පිළිබඳ උදාහරණයක් සලකා බලමු; X සංවිධානය Y අත්පත් කර ගනී, නමුත් කේතය ඒකාබද්ධ කරන අතරතුර, අතුරු මුහුණත් නොගැලපේ. Y සංවිධානයේ ගනුදෙනු ලැයිස්තුවක් සපයන අතුරු මුහුණත X සමඟ නොගැලපෙන බව උපකල්පනය කරන්න.
එබැවින්, ක්රියාත්මක කිරීම ඉතා සරල වන මෙම ගැටළුව විසඳීමට ඇඩැප්ටර සැලසුම් රටාව උපකාරී වේ.
X සංවිධානයේ සේවාලාභී යෙදුමට අවශ්ය රටා බවට පරිවර්තනය කරන Y සංවිධානයෙන් ගනුදෙනු ලැයිස්තුවක් නිර්මාණය කරමු. ඉහත පන්තිය "අනුවර්තී" ලෙස හැඳින්වේ.
public class OrgYTransactions { public List<string> GetTransactionsList() { List<string> transactions = new List<string>(); transactions.Add("Debit 1"); transactions.Add("Debit 2"); transactions.Add("Debit 3"); return transactions; } }
දෙවනුව, අපි ඉලක්ක අතුරු මුහුණතක් නිර්මාණය කරමු.
public interface ITransactions{ List<string> GetTransactions(); }
දැන් අවසාන වශයෙන්, පහත පරිදි ඇඩැප්ටර පන්තිය ක්රියාත්මක කරමු.
public class TransAdapter : OrgYTransactions, ITransactions { public List<string> GetTransactions() { return GetTransactionsList(); } }
ඉහත සියලුම ක්රියාත්මක කිරීම් සිදු කිරීමෙන් පසු, කොන්සෝල යෙදුමක ඇඩැප්ටර පන්තිය භාවිතා කරන්නේ කෙසේදැයි අපි තේරුම් ගනිමු.
class Program { static void Main(string[] args) { ITransactions adapter = new TransAdapter(); foreach (var item in adapter.GetTransactions()) { Console.WriteLine(item); } } }
ඔබ පහත භාවිතය දෙස සමීපව බැලුවහොත්, අපි තුන්වන පාර්ශ්ව පන්තියේ OrgYTransactions අතුරුමුහුණත් පෙනෙන්නේ කෙසේදැයි නොසලකා ඉලක්ක අතුරු මුහුණත ITransactions සහ Adapter class TransAdapter භාවිතා කර ඇත. එය පන්තියක අතුරුමුහුණත් සේවාදායකයාට අවශ්ය අතුරුමුහුණත් බවට පරිවර්තනය කරන ඇඩැප්ටර නිර්මාණ රටාවේ බලය එයයි.
Gang of Four ට අනුව, "Builder" නිර්මාණාත්මක රටාවක් මඟින් යමක් තැනීමට නිශ්චිත ක්රමයක් වෙන් කර නැවත භාවිතා කිරීමට ඉඩ සලසයි.
අපි මෝටර් රථයක උදාහරණයක් ගනිමු, පරිශීලකයාට මාදිලි දෙකක්, එනම් SUV සහ Sedan තැනීමට අවශ්ය විය.
ඉහත භාවිත අවස්ථාවෙහිදී ඉදිකිරීම් සැලසුම් රටාව ප්රයෝජනවත් වන අතර, අපි පියවරෙන් පියවර නිරූපණයක් බලමු.
මෝටර් රථ පන්තියට පහත ගුණාංග ඇත.
public class Car{ public string Name { get; set; } public double TopSpeed { get; set; } public bool IsSUV { get; set; } }
පළමුව, භාවිත අවස්ථාවට අනුව SUV හෝ සෙඩාන් වැනි විවිධ මෝටර් රථ මාදිලි මගින් දිගු කරන ලද වියුක්ත පන්තියේ සාදන්නා ක්රියාත්මක කරමු.
public abstract class CarBuilder { protected readonly Car _car = new Car(); public abstract void SetName(); public abstract void SetSpeed(); public abstract void SetIsSUV(); public virtual Car GetCar() => _car; }
වියුක්ත පන්තිය පහත ක්රම වලින් සමන්විත වේ
දැන්, අපි විවිධ මෝටර් රථ ආකෘති තැනීමට CarBuilder පන්තිය භාවිතා කරන කර්මාන්ත ශාලාවක් නිර්මාණය කර මෝටර් රථය සෑදූ අවස්ථාව ලබා දෙමු.
public class CarFactory { public Car Build(CarBuilder builder) { builder.SetName(); builder.SetSpeed(); builder.SetIsSUV(); return builder.GetCar(); } }
අවසාන වශයෙන්, මෝටර් රථවල විවිධ මාදිලි ක්රියාත්මක කරන්න.
public class ModelSuv : CarBuilder { public override void SetIsSUV() { _car.IsSUV = true; } public override void SetName() { _car.Name = "Maruti SUV"; } public override void SetSpeed() { _car.TopSpeed = 1000; } }
public class ModelSedan : CarBuilder { public override void SetIsSUV() { _car.IsSUV = false; } public override void SetName() { _car.Name = "Maruti Sedan"; } public override void SetSpeed() { _car.TopSpeed = 2000; } }
අවසාන වශයෙන්, කර්මාන්තශාලාවක් ආධාරයෙන් විවිධ මෝටර් රථ ආකෘති තැනීමට සැලසුම් රටා භාවිතා කරමු.Build(<model>) ක්රමය.
static void Main(string[] args) { var sedan = new ModelSedan(); var suv = new ModelSuv(); var factory = new CarFactory(); var builders = new List<CarBuilder> { suv, sedan }; foreach (var b in builders) { var c = factory.Build(b); Console.WriteLine($"The Car details" + $"\n--------------------------------------" + $"\nName: {c.Name}" + $"\nIs SUV: {c.IsSUV}" + $"\nTop Speed: {c.TopSpeed} mph\n"); } }
ඉහත භාවිතය මගින් අපට විවිධ මෝටර් රථ මාදිලි ගොඩනගන්නේ මෝස්තර රටාව භාවිතයෙන් කෙතරම් අලංකාර ලෙස ගොඩනගා ගත හැකිද යන්න පෙන්වයි.
කේත රටාව ඉතා නඩත්තු කළ හැකි සහ දිගු කළ හැකි ය. අනාගතයේදී, අපට නව මාදිලියක් සංවර්ධනය කිරීමට අවශ්ය නම්, නව මාදිලියට CarBuilder පන්තිය දිගු කිරීමට අවශ්ය නම්, එය සිදු කර ඇත.
Gang of Four ට අනුව, එය ඉල්ලීමක් ක්රියාවට නැංවීම සඳහා වගකීම් දාමයක් නිර්වචනය කරයි. වෙනත් වචන වලින් කිවහොත්, වස්තුවක් එහි වගකීම භාර ගන්නා තෙක් ඉල්ලීම එක් වස්තුවකින් තවත් වස්තුවකට යවන්න.
ඕනෑම ආයතනික සමාගමක හිමිකම් පද්ධතියක උදාහරණයක් සලකා බලමු. මෙන්න අනුමත කළ හැකි මිල පරාසයේ ලැයිස්තුව සහ කවුරුන් විසින්ද යන්න.
100–1000 Rs => Junior/Senior Engineers => Approved by Manager 1001–10000 Rs => Managers => Approved by Senior Manager
මුදල 10000 පරාසයෙන් පිටත නම්, ජ්යෙෂ්ඨ කළමනාකරුගෙන් සුවිශේෂී අනුමැතිය අවශ්ය වේ.
වගකීම් දාමයේ සැලසුම් රටාව භාවිතයෙන් ඉහත භාවිත අවස්ථාව පහසුවෙන් ක්රියාත්මක කළ හැක. එබැවින්, හිමිකම් පන්තියට පහත ගුණාංග ඇත.
public class Claim{ public int Id{get;set;} public double amount{get;set;} }
පළමුව, හිමිකම් අනුමත කරන්නෙකුට කළ හැකි කාර්යයන් නිර්වචනය කර විවිධ මට්ටම්වල සේවකයින් සඳහා ධුරාවලියක් සකස් කරමු. පහත දැක්වෙන පරිදි වියුක්ත පන්තියක් ක්රියාත්මක කරන්න
public abstract class ClaimApprover { protected ClaimApprover claimApprover; public void SetHierarchy(ClaimApprover claimApprover) { this.claimApprover = claimApprover; } public abstract void ApproveRequest(Claim claim); }
භාවිත අවස්ථාවට අනුව, අපි පන්තියේ “කනිෂ්ඨ/ජ්යෙෂ්ඨ” හිමිකම් ඉල්ලුම්කරු ධාවනය කරමු. සේවකයින්ගේ මෙම පන්තිය/නම් කිරීම කිසිදු හිමිකම් පෑමක් අනුමත කළ නොහැකි බව සලකන්න.
public class Junior : ClaimApprover { public override void ApproveRequest(Claim claim) { System.Console.WriteLine("Cannot approve"); } }
ඒ හා සමානව, කළමනාකරු සහ ජ්යෙෂ්ඨ කළමනාකරු භූමිකාවන් සඳහා ක්රියාත්මක කිරීම නිර්වචනය කරමු.
public class Manager : ClaimApprover { public override void ApproveRequest(Claim claim) { if (claim.amount >= 100 && claim.amount <= 1000) { System.Console.WriteLine($"Claim reference {claim.Id} with amount {claim.amount} is approved by Manager"); } else if (claimApprover != null) { claimApprover.ApproveRequest(claim); } } }
මුදල පරාසය මත පදනම්ව, කළමනාකරුගේ පරාසය තුළ නම්, හිමිකම් පෑම කළමනාකරු විසින් අනුමත කළ හැකි බව සලකන්න; එසේ නොමැති නම්, ඉල්ලීම ජ්යෙෂ්ඨ කළමණාකරු වෙත යවනු ලැබේ.
public class SeniorManager : ClaimApprover { public override void ApproveRequest(Claim claim) { if (claim.amount > 1000 && claim.amount <= 10000) { System.Console.WriteLine($"Claim reference {claim.Id} with amount {claim.amount} is approved by Senior Manager"); } else { System.Console.WriteLine($"Exceptional approval for Claim reference {claim.Id} with amount {claim.amount} is approved by Senior Manager"); } } }
ඒ හා සමානව, මුදල පරාසය ජ්යෙෂ්ඨ කළමනාකරු පරාසය තුළ තිබේ නම්, හිමිකම කළමනාකරු විසින් අනුමත කළ හැක; එසේ නොමැති නම්, ධූරාවලියේ අවසාන වීම, පරාසයෙන් පිටත මුදලක් සඳහා සුවිශේෂී අනුමැතියක් සිදු කෙරේ.
ClaimApprover junior = new Manager(); ClaimApprover sukhpinder = new Manager(); ClaimApprover singh = new SeniorManager(); junior.SetHierarchy(sukhpinder); sukhpinder.SetHierarchy(singh); Claim c1 = new Claim() { amount = 999, Id = 1001 }; Claim c2 = new Claim() { amount = 10001, Id = 1002 }; junior.ApproveRequest(c1); sukhpinder.ApproveRequest(c2);
Claim reference 1001 with amount 999 is approved by Manager Exceptional approval for Claim reference 1002 with amount 10001 is approved by Senior Manager
පේළිය 1 ප්රතිදානය සඳහා, මුදල පරාසය තුළ තිබූ බැවින් කළමනාකරු එය අනුමත කළේය.
පේළිය 2 ප්රතිදානය සඳහා, ජ්යෙෂ්ඨ කළමනාකරු එය අනුමත කළද, එම මුදල පරාසයෙන් පිටත විය.
Gang of Four ට අනුව, රටාව පන්ති වස්තුවකට ගතිකව අමතර වගකීම් එක් කරයි.
ලක්ෂ දහයක මෝටර් රථයක් මිලදී ගැනීමේ උදාහරණය සලකා බලමු; සමාගම පහත අමතර විශේෂාංග සපයයි.
සමහර අමතර විශේෂාංග සමඟ, මෝටර් රථයේ මුළු මිල වැඩි වේ. Decorator Pattern එක භාවිතයෙන් ඉහත භාවිත අවස්ථාව ක්රියාත්මක කරමු.
අපි ඉහත අර්ථ දක්වා ඇති භාවිත අවස්ථාව ක්රියාත්මක කරමු. පළමුව, වියුක්ත පන්තියේ මෝටර් රථයක් සහ එහි මූලික ක්රම නිර්වචනය කරන්න.
public abstract class Car{ public abstract int CarPrice(); public abstract string GetName(); }
වියුක්ත පන්තියේ මෝටර් රථයට ඉහළින් විහිදෙන කුඩා මෝටර් රථයක් සලකා බලන්න.
public class SmallCar : Car{ public override int CarPrice() => 10000; public override string GetName() => "Alto Lxi"; }
දැන්, කාර් සංරචකය භාවිතයෙන් CarDecorator පන්තිය ක්රියාත්මක කරන්න.
public class CarDecorator : Car { protected Car _car; public CarDecorator(Car car) { _car = car; } public override int CarPrice() => _car.CarPrice(); public override string GetName() =>_car.GetName(); }
දැන් අපි CarDecorator පන්තියට උරුමකම් කියන Car සඳහා ලබා ගත හැකි සෑම අමතර විශේෂාංගයක් සඳහාම වෙනම පන්තියක් නිර්මාණය කරමු.
භාවිත අවස්ථාවට අනුව, අමතර විශේෂාංග වන්නේ සන්රූෆ් සහ උසස් සංගීත පද්ධතියකි.
ලෙස ක්රම ප්රතික්ෂේප කරන්න
"උසස් සංගීත පද්ධතියක" අමතර පිරිවැය මුළු මෝටර් රථ මිලට එකතු කරන්න.
අමතර විශේෂාංග නාමය සමඟ මෝටර් රථයේ නම යාවත්කාලීන කරන්න.
public class AdvanceMusic : CarDecorator { public AdvanceMusic(Car car) : base(car) { } public override int CarPrice() => _car.CarPrice() + 3000; public override string GetName()=> "Alto Lxi with advance music system"; }
ලෙස ක්රම ප්රතික්ෂේප කරන්න
public class Sunroof : CarDecorator { public Sunroof(Car car) : base(car) { } public override int CarPrice() => _car.CarPrice() + 2000; public override string GetName() => "Alto Lxi with Sunroof"; }
SmallCar හි උදාහරණයක් සාදා මෝටර් රථයේ නම සහ මිල ප්රතිදානය කරන්න.
Car car = new SmallCar(); Console.WriteLine($"Price of car {car.GetName()} : " + car.CarPrice());
දැන්, පහත දැක්වෙන පරිදි අමතර විශේෂාංග එකතු කරමු
var car1 = new Sunroof(car); var car2 = new AdvanceMusic(car);
static void Main(string[] args) { Car car = new SmallCar(); Console.WriteLine($"Price of car {car.GetName()} : " + car.CarPrice()); var car1 = new Sunroof(car); Console.WriteLine($"Price of car {car1.GetName()} : " + car1.CarPrice()); var car2 = new AdvanceMusic(car); Console.WriteLine($"Price of car {car2.GetName()} : " + car2.CarPrice()); }
ජයවේවා..!! ඔබ සැරසිලි රටාව භාවිතයෙන් භාවිත නඩුව සාර්ථකව ක්රියාත්මක කර ඇත.
හතරේ කල්ලියට අනුව, කර්මාන්තශාලා ක්රමය මඟින් උප පංතියට කුමන පන්තියේ වස්තුවක් නිර්මාණය කළ යුතුද යන්න තීරණය කිරීමට ඉඩ සලසයි.
ඉතුරුම් සහ ජංගම ගිණුම් ලෙස ගිණුම් වර්ග ඇති ඕනෑම බැංකුවක උදාහරණයක් සලකා බලමු. දැන්, කර්මාන්තශාලා සැලසුම් රටාව භාවිතයෙන් ඉහත උදාහරණය ක්රියාත්මක කරමු
පළමුව, ගිණුම් ආකාරයේ වියුක්ත පන්තියක් සාදන්න.
public abstract class AccoutType { public string Balance { get; set; } }
පහත දැක්වෙන පරිදි AccountType වියුක්ත පන්තියට උරුමකම් කියන ජංගම සහ ඉතිරිකිරීමේ ගිණුම් පන්ති ක්රියාත්මක කරන්න.
public class SavingsAccount : AccoutType { public SavingsAccount() { Balance = "10000 Rs"; } } public class CurrentAccount : AccoutType { public CurrentAccount() { Balance = "20000 Rs"; } }
අවසාන වශයෙන්, පන්ති වස්තුවක් නිර්මාණය කිරීමට උපකාර වන කොන්ත්රාත්තුවක් සපයන කර්මාන්තශාලා අතුරුමුහුණත ක්රියාත්මක කරමු. මෙම අතුරුමුහුණත නිර්මාතෘ ලෙසද හැඳින්වේ.
public interface IAccountFactory { AccoutType GetAccoutType(string accountName); }
අවසාන වශයෙන්, පහත දැක්වෙන පරිදි නිර්මාපක අතුරුමුහුණත් ක්රමය ක්රියාත්මක කිරීමක් ලියන්න. නිර්මාතෘවරයා ක්රියාත්මක කරන පන්තිය කොන්ක්රීට් නිර්මාතෘ ලෙස හැඳින්වේ.
public class AccountFactory : IAccountFactory { public AccoutType GetAccoutType(string accountName) { if (accountName.Equals("SAVINGS", StringComparison.OrdinalIgnoreCase)) { return new SavingsAccount(); } else if (accountName.Equals("CURRENT", StringComparison.OrdinalIgnoreCase)) { return new CurrentAccount(); } else { throw new ArgumentException("Invalid account name"); } } }
ඒක තමයි. ඔබ බැංකු උදාහරණය භාවිතයෙන් කර්මාන්තශාලා ක්රමය සාර්ථකව ක්රියාත්මක කර ඇත.
ගිණුමේ නම මත පදනම්ව කුමන “ගිණුම් වර්ගය” පන්තියේ වස්තුවක් නිර්මාණය කරන්නේද යන්න උප පංතියක් විසින් තීරණය කරනු ඇත.
class Program { static void Main(string[] args) { IAccountFactory accountFactory = new AccountFactory(); var savingAccount = accountFactory.GetAccoutType("SAVINGS"); Console.WriteLine("Saving account balance: " + savingAccount.Balance); var currentAccount = accountFactory.GetAccoutType("CURRENT"); Console.WriteLine("Current account balance: " + currentAccount.Balance); } }
උදාහරණයක් ලෙස, ගිණුමේ නම "ඉතුරුම්" නම්, "SavingAccount" පන්තියේ වස්තුව නිර්මාණය කර ආපසු ලබා දෙනු ඇත.
ඒ හා සමානව, ගිණුමේ නම "CURRENT" නම්, "CurrentAccount" පන්තියේ වස්තුව ක්ෂණිකව ලබා දෙනු ඇත.
Saving account balance: 10000 Rs Current account balance: 20000 Rs
Gang of Four ට අනුව, පුනරාවර්තන රටාව මඟින් එය ක්රියාත්මක කිරීම නොදැන එකතු කිරීමේ වස්තුව ලබා ගැනීමේ ක්රියාවලියක් සපයයි.
අපි කාර් එකතු කිරීමේ ලැයිස්තුවක් සහ යතුරුපැදි මාලාවක්[] ගනිමු, අපි එකතු කිරීමේ වස්තුවක් සැලසුම් කළ යුතු අතර එමඟින් එය ලැයිස්තුවක් හෝ අරාවක් දැයි නොදැන එකතුව නැවත නැවත කළ හැකිය.
පුනරාවර්තක සැලසුම් රටාව මෙම ගැටළුව විසඳීමට උපකාරී වන අතර එහිදී සම්මත පුනරාවර්තකයක් විවිධ එකතු කිරීමේ වර්ග හරහා ගමන් කරයි.
ඉහත භාවිත අවස්ථාව සැලකිල්ලට ගනිමින්, ලැයිස්තුව සහ අරාව පුනරාවර්තකය මත වියුක්ත ස්ථරයක් ලෙස ක්රියා කරන අභිරුචි පුනරාවර්තක අතුරු මුහුණතක් අපි නිර්වචනය කරමු.
public interface IVehicleIterator{ void First(); bool IsDone(); string Next(); string Current(); }
දැන්, භාවිත අවස්ථාවට අනුව ඉහත අතුරු මුහුණත ක්රියාත්මක කරන කාර් සහ යතුරුපැදි පුනරාවර්තක ලියන්න.
public class CarIterator : IVehicleIterator { private List<string> _cars; private int _current; public CarIterator(List<string> cars) { _cars = cars; _current = 0; } public string Current() { return _cars.ElementAt(_current); } public void First() { _current = 0; } public bool IsDone() { return _current >= _cars.Count; } public string Next() { return _cars.ElementAt(_current++); } }
කාර් පුනරාවර්තකය List<string> එකතුව හරහා ක්රියාත්මක වන අතර අතුරු මුහුණත් ක්රම ක්රියාත්මක කිරීමක් සපයයි.
යතුරුපැදි පුනරාවර්තකය තන්තු[] එකතුව හරහා ක්රියාත්මක වන අතර අතුරු මුහුණත් ක්රම ක්රියාත්මක කිරීමක් සපයයි.
public class MotercycleIterator : IVehicleIterator { private string[] _motercylces; private int _current; public MotercycleIterator(string[] motercylces) { _motercylces = motercylces; _current = 0; } public string Current() { return _motercylces[_current]; } public void First() { _current = 0; } public bool IsDone() { return _current >= _motercylces.Length; } public string Next() { return _motercylces[_current++]; } }
ඉහත සියලු පුනරාවර්තක නිර්වචනය කිරීමෙන් පසුව, පුනරාවර්තක නිර්මාණය කරන සම්මත එකතු කිරීමේ වස්තු අතුරුමුහුණතක් නිර්වචනය කරන්න.
public interface IVehicleAggregate{ IVehicleIterator CreateIterator(); }
අවසාන වශයෙන්, ඉහත aggregator අතුරුමුහුණත ක්රියාත්මක කරන පන්ති ලියන්න. භාවිත අවස්ථාවට අනුව, මෝටර් රථ සහ යතුරුපැදි පන්ති දෙකම එකතු කිරීමේ අතුරුමුහුණත ක්රියාත්මක කරනු ඇත.
ඇග්රිගේටර් අතුරුමුහුණතේ ක්රමය පහත දැක්වෙන පරිදි අදාළ පුනරාවර්තකය ලබා දෙයි.
public class Car : IVehicleAggregate { private List<string> _cars; public Car() { _cars = new List<string> { "Car 1", "Car 2", "Car 3" }; } public IVehicleIterator CreateIterator() { return new CarIterator(_cars); } }
ඇග්රිගේටර් අතුරුමුහුණතේ ක්රමය පහත දැක්වෙන පරිදි අදාළ පුනරාවර්තකය ලබා දෙයි.
public class Motercycle : IVehicleAggregate { private string[] _motercycles; public Motercycle() { _motercycles = new[] { "Bike 1", "Bike 2", "Bike 3" }; } public IVehicleIterator CreateIterator() { return new MotercycleIterator(_motercycles); } }
PrintVehicles ක්රම මඟින් !iterator.isDone නම් එකතු කිරීමේ මූලද්රව්යය ප්රතිදානය කරන්නේ දැයි පරීක්ෂා කරයි. අපි කුමන එකතුවක් සමඟ ගනුදෙනු කළත්, First, IsDone, සහ Next වැනි ක්රම ක්රියාත්මක කරන්න.
static void Main(string[] args) { IVehicleAggregate car = new Vehicles.Car(); IVehicleAggregate motercycle = new Vehicles.Motercycle(); IVehicleIterator carIterator = car.CreateIterator(); IVehicleIterator motercycleIterator = motercycle.CreateIterator(); PrintVehicles(carIterator); PrintVehicles(motercycleIterator); } static void PrintVehicles(IVehicleIterator iterator) { iterator.First(); while (!iterator.IsDone()) { Console.WriteLine(iterator.Next()); } }
යටින් පවතින එකතු කිරීමේ වර්ගය අපි නොදනිමු, නමුත් එය තවමත් පුනරාවර්තන සැලසුම් රටාව හරහා පුනරාවර්තනය වේ. ඔබ ඉදිරියට ගොස් ධාවනය කරන්නේ නම්, එය පහත ප්රතිදානය පෙන්වයි.
Gang of Four ට අනුව, මැදිහත්කරු රටාව එකිනෙකා සමඟ වස්තු අන්තර්ක්රියා සංග්රහ කරයි.
වස්තු අන්තර්ක්රියා සංග්රහ කිරීමෙන් ලිහිල් සම්බන්ධිත යෙදුම් සැලසුම් කිරීමට මැදිහත්කරු සැලසුම් රටාව අපට උපකාර කරයි.
සහභාගිවන්නන් ලියාපදිංචි වන සංවාද කුටියක උදාහරණයක් සහ කාර්යක්ෂමව සන්නිවේදනය කරන්නේ කෙසේද යන්න සලකා බලමු.
මැදිහත්කරු සැලසුම් රටාව භාවිතයෙන් පහත කතාබස් සංවාදය ක්රියාත්මක කිරීමට අවශ්ය වේ.
David to Scott: 'Hey' Scott to David: 'I am good how about you.' Jennifer to Ashley: 'Hey ashley... david is back in the group' Jennifer to David: 'Where have you been?' Ashley to David: 'How come you aren't active here anymore?'
මූලික පියවර වන්නේ කතාබස් කාමරයක් තුළ භාවිතා කරන පරිශීලක නාම ලැයිස්තුවක් නිර්මාණය කිරීමයි. ඒ සඳහා වූ මහජන සටහනක් පහත දැක්වේ.
public enum Username{ Ashley, David, Jennifer, Scott }
දැන්, පළමුව සහ ප්රධාන වශයෙන්, chatroom හි වියුක්ත තට්ටුවක් ක්රියාත්මක කරන්න.
public abstract class AChatroom { public abstract void Register(User user); public abstract void Post(string fromUser, string toUser, string msg); }
සහ වියුක්ත ක්රම නිර්වචනය කරන පන්තියක්. ශබ්ද කෝෂයේ පරිශීලකයා සිටී නම් ක්රම වලංගු වේ. උදාහරණයක් ලෙස, පරිශීලකයා දැනටමත් සිටීද නැද්ද යන්න ලියාපදිංචි කිරීමේ ක්රමය වලංගු කරයි. නොපවතියි නම්, පරිශීලකයා පමණක් චැට් රූම් හි ලියාපදිංචි කරන්න.
public class Chatroom : AChatroom { private Dictionary<string, User> _users = new Dictionary<string, User>(); public override void Post(string fromUser, string toUser, string msg) { User participant = _users[toUser]; if (participant != null) { participant.DM(fromUser, msg); } } public override void Register(User user) { if (!_users.ContainsValue(user)) { _users[user.Name] = user; } user.Chatroom = this; } }
අවසාන වශයෙන්, කතාබස් කාමරය තුළ පරිශීලකයෙකුට පණිවිඩයක් පළ කිරීම හෝ වෙනත් පරිශීලකයෙකුගෙන් DM එකක් ලබා ගැනීම වැනි පරිශීලකයාට කළ හැකි ක්රියාවන් ක්රියාත්මක කරමු.
public class User { private Chatroom _chatroom; private string _name; public User(string name) => this._name = name; public string Name => _name; public Chatroom Chatroom { set { _chatroom = value; } get => _chatroom; } public void Post(string to, string message) => _chatroom.Post(_name, to, message); public virtual void DM(string from, string message) => Console.WriteLine("{0} to {1}: '{2}'", from, Name, message); }
static void Main(string[] args) { Chatroom chatroom = new Chatroom(); User Jennifer = new UserPersona(Username.Jennifer.ToString()); User Ashley = new UserPersona(Username.Ashley.ToString()); User David = new UserPersona(Username.David.ToString()); User Scott = new UserPersona(Username.Scott.ToString()); chatroom.Register(Jennifer); chatroom.Register(Ashley); chatroom.Register(David); chatroom.Register(Scott); David.Post(Username.Scott.ToString(), "Hey"); Scott.Post(Username.David.ToString(), "I am good how about you."); Jennifer.Post(Username.Ashley.ToString(), "Hey ashley... david is back in the group"); Jennifer.Post(Username.David.ToString(), "Where have you been?"); Ashley.Post(Username.David.ToString(), "How come you aren't active here anymore?"); Console.ReadKey(); }
වැඩසටහන ක්රියාත්මක කිරීම විස්තර කරන්නේ පරිශීලක පන්තියේ පෝස්ට් ක්රමය පමණි.
ප්රතිදානය: ඉහත වැඩසටහන් ක්රියාත්මක කිරීමේ චැට් රූම් ඉතිහාසය
David to Scott: 'Hey' Scott to David: 'I am good how about you.' Jennifer to Ashley: 'Hey ashley... david is back in the group' Jennifer to David: 'Where have you been?' Ashley to David: 'How come you aren't active here anymore?'
Gang of Four ට අනුව, නිරීක්ෂක රටාව මගින් පරායත්තතාව b/w වස්තු දෙකක් හෝ වැඩි ගණනක් නිර්වචනය කරයි. එබැවින්, එක් වස්තුවක තත්වයක් වෙනස් වූ විට, එහි සියලු යැපෙන්නන්ට දැනුම් දෙනු ලැබේ.
වෙනත් වචන වලින් කිවහොත්, එක් වස්තුවක වෙනසක් තවත් වස්තුවක දැනුම්දීම ආරම්භ කරයි.
" x " අනුගාමිකයින් සංඛ්යාවක් සිටින Instagram කීර්තිමත් බලපෑම් කරන්නෙකුගේ උදාහරණයක් ගනිමු. ඉතින්, කීර්තිමත් පුද්ගලයා පෝස්ටුවක් එකතු කරන මොහොතේ, සියලු අනුගාමිකයින්ට දැනුම් දෙනු ලැබේ.
අපි Observer Design Pattern භාවිතයෙන් ඉහත සඳහන් කළ භාවිත අවස්ථාව ක්රියාත්මක කරමු.
භාවිත අවස්ථාවට අනුව, පළමුවැන්න කීර්තිමත් පුද්ගලයෙකුට කළ හැකි ක්රියා අඩංගු අතුරු මුහුණතක් ක්රියාත්මක කරයි. එය " විෂය " ලෙස හැඳින්වේ.
public interface ICelebrityInstagram{ string FullName { get; } string Post { get; set; } void Notify(string post); void AddFollower(IFollower fan); void RemoveFollower(IFollower fan); }
දැනුම් දෙන්න: සියලුම අනුගාමිකයින්ට දැනුම් දීමට.
AddFollower: කීර්තිමත් ලැයිස්තුවට නව අනුගාමිකයෙකු එක් කරන්න.
RemoveFollower: කීර්තිමත් ලැයිස්තුවෙන් අනුගාමිකයෙකු ඉවත් කරන්න.
දැන්, දැනුම්දීම සඳහා "යාවත්කාලීන" සාමාජික ශ්රිතය අඩංගු නිරීක්ෂක "IFollower" අතුරුමුහුණත ක්රියාත්මක කරන්න.
public interface IFollower{ void Update(ICelebrityInstagram celebrityInstagram); }
අවසාන වශයෙන්, " විෂය " සහ " නිරීක්ෂක " යන දෙකටම "කොන්ක්රීට් ක්රියාත්මක කිරීම" ක්රියාත්මක කිරීමට කාලයයි.
එය කොන්සෝලයට ප්රසිද්ධ පුද්ගලයින්ගේ නම සහ පළ කිරීම ප්රතිදානය කරන යාවත්කාලීන සාමාජික ශ්රිතය ක්රියාත්මක කිරීමක් සපයයි.
public class Follower : IFollower { public void Update(ICelebrityInstagram celebrityInstagram) { Console.WriteLine($"Follower notified. Post of {celebrityInstagram.FullName}: " + $"{celebrityInstagram.Post}"); } }
public class Sukhpinder : ICelebrityInstagram { private readonly List<IFollower> _posts = new List<IFollower>(); private string _post; public string FullName => "Sukhpinder Singh"; public string Post { get { return _post; } set { Notify(value); } } public void AddFollower(IFollower follower) { _posts.Add(follower); } public void Notify(string post) { _post = post; foreach (var item in _posts) { item.Update(this); } } public void RemoveFollower(IFollower follower) { _posts.Remove(follower); } }
පහත ප්රකාශය ක්රියාත්මක වන සෑම විටම sukhpinder.Post = "මම නිර්මාණ රටා වලට කැමතියි." එක් එක් අනුගාමිකයෙකු සඳහා යාවත්කාලීන ක්රමය ක්රියාරම්භ කරනු ලැබේ, එනම්, සෑම අනුගාමික වස්තුවක්ම “සුක්පින්ඩර්” වෙතින් නව පළ කිරීමක් පිළිබඳව දැනුම් දෙනු ලැබේ.
static void Main(string[] args) { var sukhpinder = new Sukhpinder(); var firstFan = new Follower(); var secondFan = new Follower(); sukhpinder.AddFollower(firstFan); sukhpinder.AddFollower(secondFan); sukhpinder.Post = "I love design patterns."; Console.Read(); }
ප්රාථමික පද්ධතියේ කොටසක් නොවන ආකෘතිවලින් එම දත්ත භාවිතා කිරීමට සහ සැකසීමට රටා ගැලපීම ඵලදායී ක්රමයක් සපයන ආකාරය ලිපිය විස්තර කරයි.
අපි Toll කැල්කියුලේටරයේ උදාහරණයක් ගෙන ඒ සඳහා ඇල්ගොරිතමයක් ලිවීමට රටා ගැලපීම උපකාර වන ආකාරය බලමු.
public class Car { public int PassengerCount { get; set; } } public class DeliveryTruck { public int Weight { get; set; } } public class Taxi { public int Fare { get; set; } } public class Bus { public int Capacity { get; set; } public int RidersCount { get; set; } }
උදාහරණ 1: පහත කොන්දේසි අනුව ගාස්තු ගාස්තු ගණනය කරන්න:
- වාහනය කාර් එකක් නම් => 100 රු
- වාහනය DeliveryTruck නම් => 200 රු
- වාහනය Bus => 150 රු
- වාහනය කුලී රථයක් නම් => 120 රු
වාහන වර්ගය Car 100 සමඟ ගැලපේ නම් ආපසු එවනු ලැබේ. ශුන්ය සහ {} වස්තු වර්ගය සඳහා පෙරනිමි අවස්ථා බව සලකන්න.
එසේම, "_" පෙරනිමි අවස්ථාව වැඩසටහන්ගත කිරීමට භාවිතා කළ හැක. නව ස්විච් සින්ටැක්ස් වෙත යොමු වන්න.
එය වඩාත් පිරිසිදු සහ කාර්යක්ෂම කේතීකරණ ක්රමයක් වන අතර ස්විච වාක්ය ඛණ්ඩය තුළ තනි අකුරු විචල්ය නම් භාවිතා කිරීම ද නිර්දේශ කර ඇත.
public static int TollFare(Object vehicleType) => vehicleType switch { Car c => 100, DeliveryTruck d => 200, Bus b => 150, Taxi t => 120, null => 0, { } => 0 };
කොන්සෝල යෙදුම් ආස්ථානයකින් උදාහරණ පරීක්ෂා කරන්න. පහත කේතය ප්රධාන ක්රමයෙන් ඉහත රටා-ගැලපෙන ශ්රිතය අමතන්නේ කෙසේදැයි විදහා දක්වයි.
var car = new Car(); var taxi = new Taxi(); var bus = new Bus(); var truck = new DeliveryTruck(); Console.WriteLine($"The toll for a car is {TollFare(car)}"); Console.WriteLine($"The toll for a taxi is {TollFare(taxi)}"); Console.WriteLine($"The toll for a bus is {TollFare(bus)}"); Console.WriteLine($"The toll for a truck is {TollFare(truck)}");
The toll for a car is 100 The toll for a taxi is 120 The toll for a bus is 150 The toll for a truck is 200
උදාහරණ 2: වාහන වර්ගය මත පදනම්ව පදිංචි මිල එකතු කරන්න
- "නැහැ" මගීන් සහිත කාර් සහ කුලී රථ සඳහා අමතර රු. 10ක් ගෙවයි.
- මගීන් දෙදෙනෙකු සිටින කාර් සහ කුලී රථ සඳහා රුපියල් 10 ක වට්ටමක් ලැබේ.
- මගීන් තිදෙනෙකු හෝ වැඩි ගණනක් සිටින කාර් සහ කුලී රථ සඳහා රුපියල් 20 ක වට්ටමක් ලැබේ.
- මගීන්ගෙන් 50% ට අඩු බස් රථ සඳහා අමතර රු. 30 ක් ගෙවනු ලැබේ.
- මගීන්ගෙන් 90% කට වඩා වැඩි බස් රථ සඳහා රුපියල් 40 ක වට්ටමක් ලැබේ.
- රාත්තල් 5000ට වැඩි ට්රක් රථ සඳහා රුපියල් 100ක් වැඩිපුර අය කෙරේ.
- රාත්තල් 3000ට අඩු සැහැල්ලු ට්රක් රථ, රුපියල් 20ක වට්ටමක් ලබා දී ඇත.
තනි සහ බහු දේපල පන්ති සමඟ රටා-ගැලපෙන වාක්ය ඛණ්ඩය වෙත යොමු වන්න. සබැඳිය
Car { PassengerCount: 0 } => 100 + 10, Car { PassengerCount: 1 } => 100, Car { PassengerCount: 2 } => 100 - 10, Car c => 100 - 20,
Taxi {Fare:0 }=>100+10, Taxi { Fare: 1 } => 100, Taxi { Fare: 2 } => 100 - 10, Taxi t => 100 - 20,
Bus b when ((double)b.RidersCount / (double)b.Capacity) < 0.50 => 150 + 30, Bus b when ((double)b.RidersCount / (double)b.Capacity) > 0.90 => 150 - 40, Bus b => 150,
DeliveryTruck t when (t.Weight > 5000) => 200 + 100, DeliveryTruck t when (t.Weight < 3000) => 200 - 20, DeliveryTruck t => 200,
පහත උදාහරණය රටා ගැලපීමේ වාසි ඉස්මතු කරයි: රටා අතු පිළිවෙලට සම්පාදනය කර ඇත. සම්පාදකය ළඟා විය නොහැකි කේතය ගැන ද අනතුරු අඟවයි.
public static int OccupancyTypeTollFare(Object vehicleType) => vehicleType switch { Car { PassengerCount: 0 } => 100 + 10, Car { PassengerCount: 1 } => 100, Car { PassengerCount: 2 } => 100 - 10, Car c => 100 - 20, Taxi { Fare: 0 } => 100 + 10, Taxi { Fare: 1 } => 100, Taxi { Fare: 2 } => 100 - 10, Taxi t => 100 - 20, Bus b when ((double)b.RidersCount / (double)b.Capacity) < 0.50 => 150 + 30, Bus b when ((double)b.RidersCount / (double)b.Capacity) > 0.90 => 150 - 40, Bus b => 150, DeliveryTruck t when (t.Weight > 5000) => 200 + 100, DeliveryTruck t when (t.Weight < 3000) => 200 - 20, DeliveryTruck t => 200, null => 0, { } => 0, };
කොන්සෝල යෙදුම් ආස්ථානයකින් උදාහරණ පරීක්ෂා කරන්න. පහත කේතය ප්රධාන ක්රමයෙන් ඉහත රටා ගැළපෙන ශ්රිතය අමතන්නේ කෙසේදැයි විදහා දක්වයි.
var car1 = new Car{ PassengerCount=2}; var taxi1 = new Taxi { Fare = 0 }; var bus1 = new Bus { Capacity = 100, RidersCount = 30 }; var truck1 = new DeliveryTruck { Weight = 30000 }; Console.WriteLine($"The toll for a car is {OccupancyTypeTollFare(car1)}"); Console.WriteLine($"The toll for a taxi is {OccupancyTypeTollFare(taxi1)}"); Console.WriteLine($"The toll for a bus is {OccupancyTypeTollFare(bus1)}"); Console.WriteLine($"The toll for a truck is {OccupancyTypeTollFare(truck1)}");
The toll for a car is 90 The toll for a taxi is 110 The toll for a bus is 180 The toll for a truck is 300
"රටාව ගැලපීම මඟින් කේතය වඩාත් කියවිය හැකි අතර ඔබට ඔබේ පන්තිවලට කේතය එක් කළ නොහැකි විට වස්තු-නැඹුරු තාක්ෂණික ක්රම සඳහා විකල්පයක් ඉදිරිපත් කරයි."
Gang of Four — Singleton නිර්මාණ රටාව යම් පන්තියකට ඇත්තේ එක් අවස්ථාවක්/වස්තුවක් සහ ගෝලීය ප්රවේශ ලක්ෂ්යයක් පමණක් බව සහතික කරයි.
විශේෂිත පන්තියක එක් වස්තුවකට වඩා ක්ෂණිකව ඉවත් කිරීම සඳහා Singleton පන්ති භාවිතා කරයි.
public class SingletonExample { private string Name { get; set; } = "Hello from singleton"; private static SingletonExample _instance; public static SingletonExample Instance { get { if (_instance == null) { _instance = new SingletonExample(); } return _instance; } } public SingletonExample() { } public string GetName() => Name; }
අපි සිංගල්ටන් පන්තියට දෙවරක් කතා කර ආපසු ලබා දුන් අවස්ථාව වෙනස් විචල්ය දෙකකට පවරමු. අවසාන වශයෙන්, theObject.Equals ශ්රිතය භාවිතයෙන් වස්තු දෙකම සමානදැයි පරීක්ෂා කරන්න.
static void Main(string[] args) { var response = SingletonExample.Instance; Console.WriteLine(response); var response1 = SingletonExample.Instance; Console.WriteLine(response1); Console.WriteLine(Object.Equals(response1, response)); }
කොන්සෝල ප්රතිදානය සත්ය වේ; සුභ පැතුම්. ඔබ Singleton Pattern සාර්ථකව ක්රියාත්මක කර ඇත.
ඉහත පන්තිය තනි පන්තිය ලෙස හැඳින්වේ, නමුත් දැනට එය නූල් ආරක්ෂිත නොවේ. බහු-නූල් පරිසරයක් තුළ, නූල් දෙකක් එකවර නම් (_instance == null) ප්රකාශය වැදිය හැකි අතර, අපට තනි පන්තියක අවස්ථා කිහිපයක් තිබීම අවසන් වනු ඇත.
ආරක්ෂිත නූල් සඳහා එක් මාර්ගයක් වන්නේ අගුළු යාන්ත්රණයක් භාවිතා කිරීමයි, අනෙක් ක්රමය නම් පිරිසිදු හා වඩා කාර්යක්ෂම ප්රවේශයක් සඳහා කියවීමට පමණක් අවස්ථාවක් ලබා දීමයි.
public class ThreadSafeSingleton { private static readonly ThreadSafeSingleton _instance = new ThreadSafeSingleton(); public static ThreadSafeSingleton Instance { get { return _instance; } } public ThreadSafeSingleton() { } }
https://github.com/ssukhpinder/DesignPatterns
මෙවැනි නව ව්යාපෘති පවත්වාගෙන යාමට සහ ගොඩනැගීමට අනුග්රාහකත්වය මට උපකාර කරයි.
🙏 ඔබ Pay, Noticed, හෝ මගේ වෙනත් ව්යාපෘති භාවිතා කරන්නේ නම්, කුඩා දායකත්වයක් යනු මුළු විශාල ප්රමාණයකි. තනිවම, විවෘත මූලාශ්රය බිල් ගෙවන්නේ නැත. ඔබගේ උදව්වෙන්, මගේ කාර්යය දිගටම කරගෙන යාමට හැකි වනු ඇතැයි බලාපොරොත්තු වන අතර, මට සැබෑ රැකියාවක් ලබා ගැනීමට යාමට සිදු නොවනු ඇත.
C# ප්රජාවේ කොටසක් වීම ගැන ඔබට ස්තුතියි!