সিকিউআরএস + ইএস-তে কোনও অবজেক্টটি কোথায় সম্পূর্ণরূপে শুরু করা উচিত: কনস্ট্রাক্টরে, বা প্রথম ইভেন্টটি প্রয়োগ করার সময়?


9

ওওপি সম্প্রদায়ের মধ্যে বিস্তৃত চুক্তি দেখা যাচ্ছে যে শ্রেণি নির্মাতাকে কোনও বিষয় আংশিক বা পুরোপুরি অস্বীকার করা উচিত নয়।

"আরম্ভ" বলতে আমি কী বুঝি? মোটামুটিভাবে বলতে গেলে, পারমাণবিক প্রক্রিয়া যা নতুনভাবে তৈরি করা একটি বস্তুকে এমন একটি রাজ্যে নিয়ে আসে যেখানে এর সমস্ত শ্রেণীর আগ্রাসন থাকে। এটি প্রথম জিনিসটি হওয়া উচিত যা কোনও বস্তুর সাথে ঘটে, (এটি কেবল প্রতিটি বস্তুতে একবার চালানো উচিত) এবং কোনও অ-আরম্ভীকৃত বস্তু ধরে রাখার অনুমতি দেওয়া উচিত নয়। (এইভাবে ক্লাস কনস্ট্রাক্টরে অবজেক্ট ইনিশিয়ালেশন সম্পাদন করার জন্য প্রায়শই পরামর্শ the একই কারণে, Initializeপদ্ধতিগুলি প্রায়শই ভ্রূণ হয়, কারণ এগুলি পরমাণুটিকে পৃথক করে দেয় এবং এটি কোনও অবজেক্টকে ধরে রাখা এবং ব্যবহার সম্ভব করে তোলে যা এখনও অবধি নেই is একটি সংজ্ঞায়িত অবস্থায়।)

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

দ্রষ্টব্য: আমি "সমষ্টিগত মূল" শব্দটি ব্যবহার করা থেকে বিরত রয়েছি। আপনি যদি পছন্দ করেন তবে আপনি যখনই "অবজেক্ট" পড়েন তখন এটিকে বিকল্প দিন।

আলোচনার উদাহরণ: ধরুন যে প্রতিটি বস্তু স্বতন্ত্রভাবে কিছু অস্বচ্ছ Idমান দ্বারা চিহ্নিত করা হয়েছে (জিইউডি ভাবেন)। ইভেন্ট স্টোরের মধ্যে সেই সামগ্রীর স্টেটের পরিবর্তনের প্রতিনিধিত্বকারী একটি ইভেন্ট স্ট্রিম একই Idমান দ্বারা চিহ্নিত করা যেতে পারে : (আসুন সঠিক ইভেন্ট ক্রমের বিষয়ে চিন্তা করবেন না))

interface IEventStore
{
    IEnumerable<IEvent> GetEventsOfObject(Id objectId); 
}

আরও ধরে নিন যে দুটি বস্তুর ধরণ রয়েছে Customerএবং ShoppingCart। আসুন এতে ফোকাস করুন ShoppingCart: তৈরি করার সময় শপিং কার্টগুলি খালি থাকে এবং অবশ্যই এক গ্রাহকের সাথে যুক্ত থাকতে হবে। শেষ বিটটি একটি শ্রেণির আক্রমণকারী: একটি ShoppingCartঅবজেক্ট যা কোনওটির সাথে সম্পর্কিত নয় তা Customerঅবৈধ অবস্থায় রয়েছে।

Traditionalতিহ্যবাহী ওওপি-তে, কেউ এটি নির্মাণকারীর মধ্যে মডেল করতে পারে:

partial class ShoppingCart
{
    public Id Id { get; private set; }
    public Customer Customer { get; private set; }

    public ShoppingCart(Id id, Customer customer)
    {
        this.Id = id;
        this.Customer = customer;
    }
}

তবে আমি কী ক্ষতির মধ্যে আছি যে কীভাবে পিছিয়ে পড়া শুরু না করে সিকিউআরএস + ইএস-এ এটি মডেল করা যায়। যেহেতু এই সাধারণ সূচনাটি কার্যকরভাবে একটি রাষ্ট্রীয় পরিবর্তন, তাই এটি কী কোনও ইভেন্ট হিসাবে মডেলিং করতে হবে না?:

partial class CreatedEmptyShoppingCart
{
    public ShoppingCartId { get; private set; }
    public CustomerId { get; private set; }
}
// Note: `ShoppingCartId` is not actually required, since that Id must be
// known in advance in order to fetch the event stream from the event store.

স্পষ্টতই কোনও ShoppingCartবস্তুর ইভেন্টের প্রবাহের এটি প্রথম ইভেন্ট হতে হবে এবং ইভেন্টটি প্রয়োগ হওয়ার পরে that অবজেক্টটি কেবলমাত্র আরম্ভ করা হবে।

সুতরাং যদি সূচনাটি ইভেন্ট স্ট্রিম "প্লেব্যাক" এর অংশ হয়ে যায় (এটি একটি খুব জেনেরিক প্রক্রিয়া যা সম্ভবত একইরকম কাজ করবে, কোনও Customerবস্তু বা কোনও ShoppingCartঅবজেক্টের জন্য বা অন্য কোনও অবজেক্টের ক্ষেত্রে এটিই হোক ...)

  • কনস্ট্রাক্টরটি কি প্যারামিটার-কম হওয়া উচিত এবং কিছু না করে সমস্ত কাজ কিছু void Apply(CreatedEmptyShoppingCart)পদ্ধতিতে ফেলে রাখা (যা অনেকটা একইসাথে Initialize())?
  • অথবা কনস্ট্রাক্টরের কোনও ইভেন্ট স্ট্রিম গ্রহণ করা উচিত এবং এটিকে আবার খেলানো উচিত (যা আবার সূচনাকে পারমাণবিক করে তোলে, তবে এর অর্থ প্রতিটি শ্রেণীর কনস্ট্রাক্টরের একই জেনেরিক "প্লে ব্যাক অ্যান্ড অ্যাপ্লিকেশন" লজিক থাকে, অর্থাৎ অযাচিত কোড ডুপ্লিকেশন)?
  • অথবা উভয় এমন একটি traditional তিহ্যবাহী ওওপি নির্মাণকারী (উপরে বর্ণিত হিসাবে) থাকা উচিত যা সঠিকভাবে বস্তুটি আরম্ভ করে, এবং তারপরে সমস্ত ইভেন্টগুলি প্রথমে এর সাথে void Apply(…)যুক্ত হয়?

আমি সম্পূর্ণরূপে কার্যকরী ডেমো বাস্তবায়ন সরবরাহের উত্তর আশা করি না; আমি ইতিমধ্যে খুব খুশি যদি কেউ যেখানে আমার যুক্তি ত্রুটিপূর্ণ হয়, অথবা কিনা বস্তুর আরম্ভের সত্যিই ব্যাখ্যা হতে পারে হতে চাই হয় একটি "ব্যথা পয়েন্ট" সবচেয়ে CQRS + + ইএস বাস্তবায়নের হবে।

উত্তর:


3

সিকিউআরএস + ইএস করার সময় আমি পাবলিক কনস্ট্রাক্টর মোটেও পছন্দ না করি। আমার সামগ্রিক শিকড়গুলি তৈরি করা কারখানার মাধ্যমে করা উচিত (এটির মতো সহজ যথেষ্ট নির্মাণের জন্য) বা একজন নির্মাতা (আরও জটিল সামগ্রিক শিকড়ের জন্য)।

কীভাবে আসলে বস্তুর সূচনা করা যায় তা একটি বাস্তবায়ন বিশদ। গলি "do আরম্ভ ব্যবহার করবেন" -advice সম্পর্কে এই প্রোগ্রামটিতে হয় প্রকাশ্য ইন্টারফেসগুলি । আপনারা এমনটি আশা করা উচিত নয় যে আপনার কোডটি ব্যবহার করেন এমন কেউ জানেন যে তাদের অবশ্যই সিক্রেটইনিটায়ালাইজমেডোড 42 (বুল, ইনট, স্ট্রিং) কল করতে হবে - এটি খারাপ পাবলিক এপিআই ডিজাইন। তবে যদি আপনার ক্লাসটি কোনও পাবলিক কনস্ট্রাক্টর সরবরাহ না করে তবে এর পরিবর্তে পদ্ধতিতে ক্রিয়েটনিউশপিংকার্ট (স্ট্রিং) সহ একটি শপিংকার্টফ্যাক্টরি থাকে তবে সেই কারখানার প্রয়োগটি খুব ভালভাবে কোনও প্রারম্ভিককরণ / কনস্ট্রাক্টর ম্যাজিক লুকিয়ে রাখতে পারে যা আপনার ব্যবহারকারীর জানার দরকার পরে না don't সম্পর্কে (এইভাবে একটি দুর্দান্ত পাবলিক এপিআই সরবরাহ করছে, তবে আপনাকে পর্দার পিছনে আরও উন্নত অবজেক্ট তৈরি করার অনুমতি দেয়)

কারখানাগুলি লোকেদের মনে করে খারাপ প্রতিক্রিয়া পেয়েছে যে তাদের মধ্যে অনেকগুলি রয়েছে, তবে সঠিকভাবে ব্যবহৃত হয়েছে তারা সহজেই বোঝা যায় এমন একটি সহজ সরল API এর পিছনে প্রচুর জটিলতা দূরে রাখতে পারে। এগুলি ব্যবহার করতে ভয় পাবেন না, এগুলি একটি শক্তিশালী সরঞ্জাম যা আপনাকে জটিল অবজেক্ট নির্মাণ আরও সহজ করতে সহায়তা করতে পারে - যতক্ষণ আপনি কোডের আরও কয়েকটি লাইন নিয়ে বেঁচে থাকতে পারেন।

কোডটি ন্যূনতম লাইনের সাহায্যে সমস্যাটি কে সমাধান করতে পারে তা দেখার জাতি নয় - তবে এটি কে সর্বসাধারণের সর্বজনীন এপিআই তৈরি করতে পারে তা একটি চলমান প্রতিযোগিতা! ;)

সম্পাদনা করুন: কীভাবে এই নিদর্শনগুলি প্রয়োগ করা যেতে পারে সে সম্পর্কে কয়েকটি উদাহরণ যুক্ত করা

আপনার যদি কেবলমাত্র একটি "সহজ" সমষ্টিগত নির্মাণকারীর রয়েছে যা বেশ কয়েকটি প্রয়োজনীয় পরামিতি রয়েছে আপনি কেবলমাত্র একটি খুব বেসিক কারখানার প্রয়োগের সাথে যেতে পারেন, এই লাইনগুলির পাশাপাশি কিছু

public class FooAggregate {
     internal FooAggregate() { }

     public int A { get; private set; }
     public int B { get; private set; }

     internal Handle(FooCreatedEvent evt) {
         this.A = a;
         this.B = b;
     }
}

public class FooFactory {
    public FooAggregate Create(int a, int b) {
        var evt = new FooCreatedEvent(a, b);
        var result = new FooAggregate();
        result.Handle(evt);
        DomainEvents.Register(result, evt);
        return result;
    }
}

অবশ্যই, FooCreatedEvent তৈরির ক্ষেত্রে আপনি ঠিক কীভাবে ভাগ করবেন তা আপনার ক্ষেত্রে। কেউ FooAggregate (FooCreatedEvent) কনস্ট্রাক্টর থাকার জন্য, বা ইভেন্ট তৈরি করে এমন একটি FooAgregate (int, int) কনস্ট্রাক্টর থাকার ক্ষেত্রেও কেস করতে পারে। ঠিক কীভাবে আপনি এখানে দায়িত্ব বিভাজন করতে বেছে নিচ্ছেন তা আপনার আপত্তি সবচেয়ে পরিষ্কার এবং আপনি কীভাবে আপনার ডোমেন ইভেন্টের নিবন্ধকরণটি প্রয়োগ করেছেন তা নির্ভর করে। আমি প্রায়শই কারখানাটি ইভেন্টটি তৈরি করতে পছন্দ করি - তবে ঘটনাটি তৈরি করা এখন একটি অভ্যন্তরীণ বাস্তবায়নের বিশদ যা আপনার বাহ্যিক ইন্টারফেস পরিবর্তন না করে আপনি যে কোনও সময় পরিবর্তন এবং রিফ্যাক্টর করতে পারেন it's এখানে একটি গুরুত্বপূর্ণ বিশদটি হ'ল সমষ্টিতে কোনও পাবলিক কনস্ট্রাক্টর নেই এবং সমস্ত সেটটারগুলি ব্যক্তিগত। আপনি চান না যে কেউ এগুলি বাহ্যিকভাবে ব্যবহার করবে।

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

এই উদাহরণটি কিছুটা জোর করা হয়েছে যেহেতু এটি তৈরি করা শ্রেণিটি খুব জটিল নয়, তবে আপনি আশাবাদী ধারণাটি উপলব্ধি করতে পারেন এবং এটি আরও জটিল নির্মাণ কাজগুলিকে কীভাবে সহজসাধ্য করবে তা দেখতে পারেন can

public class FooBuilder {
    private int a;
    private int b;   

    public FooBuilder WithA(int a) {
         this.a = a;
         return this;
    }

    public FooBuilder WithB(int b) {
         this.b = b;
         return this;
    }

    public FooAggregate Build() {
         if(!someChecksThatWeHaveAllState()) {
              throw new OmgException();
         }

         // Some hairy logic on how to create a FooAggregate and the creation events from our state
         var foo = new FooAggregate(....);
         foo.PlentyOfHairyInitialization(...);
         DomainEvents.Register(....);

         return foo;
    }
}

এবং তারপরে আপনি এটির মতো ব্যবহার করুন

var foo = new FooBuilder().WithA(1).Build();

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

এই পথে যাওয়ার জন্য গুরুত্বপূর্ণ অবলম্বন হ'ল:

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

আশা করি এটি আরও কিছুটা সহায়তা করে, অন্যথায় মন্তব্যে স্পষ্টতার জন্য জিজ্ঞাসা করুন :)


+1, আমি এমনকি কারখানার সম্ভাব্য নকশা সমাধান হিসাবে কখনও ভাবি নি। যদিও একটি জিনিস: এটি মনে হচ্ছে যেন ফ্যাক্টরিগুলি জনসাধারণের ইন্টারফেসে মূলত একই জায়গা নেয় যা সামগ্রিক নির্মাতারা (+ সম্ভবত কোনও Initializeপদ্ধতি) দখল করে নিয়েছিল। এটি আমাকে প্রশ্নের দিকে নিয়ে যায়, আপনার এমন কারখানাটি দেখতে কেমন হতে পারে?
stakx

3

আমার মতে, আমি মনে করি উত্তরটি বিদ্যমান সংস্থাগুলির জন্য আপনার পরামর্শ # 2 এর মতো; নতুন সমষ্টিগুলির জন্য আরও # 3 এর মতো (তবে ইভেন্টটি আপনার পরামর্শ অনুসারে প্রক্রিয়া করা হচ্ছে)।

এখানে কিছু কোড রয়েছে আশা করি এটি কিছুটা সহায়ক হবে।

public abstract class Aggregate
{
    Dictionary<Type, Delegate> _handlers = new Dictionary<Type, Delegate>();

    protected Aggregate(long version = 0)
    {
        this.Version = version;
    }

    public long Version { get; private set; }

    protected void Handles<TEvent>(Action<TEvent> action)
        where TEvent : IDomainEvent            
    {
        this._handlers[typeof(TEvent)] = action;
    }

    private IList<IDomainEvent> _pendingEvents = new List<IDomainEvent>();

    // Apply a new event, and add to pending events to be committed to event store
    // when transaction completes
    protected void Apply(IDomainEvent @event)
    {
        this.Invoke(@event);
        this._pendingEvents.Add(@event);
    }

    // Invoke handler to change state of aggregate in response to event
    // Event may be an old event from the event store, or may be an event triggered
    // during the lifetime of this instance.
    protected void Invoke(IDomainEvent @event)
    {
        Delegate handler;
        if (this._handlers.TryGetValue(@event.GetType(), out handler))
            ((Action<TEvent>)handler)(@event);
    }
}

public class ShoppingCart : Aggregate
{
    private Guid _id, _customerId;

    private ShoppingCart(long version = 0)
        : base(version)
    {
         // Setup handlers for events
         Handles<ShoppingCartCreated>(OnShoppingCartCreated);
         // Handles<ItemAddedToShoppingCart>(OnItemAddedToShoppingCart);  
         // etc...
    } 

    public ShoppingCart(long version, IEnumerable<IDomainEvent> events)
        : this(version)
    {
         // Replay existing events to get current state
         foreach (var @event in events)
             this.Invoke(@event);
    }

    public ShoppingCart(Guid id, Guid customerId)
        : this()
    {
        // Process new event, changing state and storing event as pending event
        // to be saved when aggregate is committed.
        this.Apply(new ShoppingCartCreated(id, customerId));            
    }            

    private void OnShoppingCartCreated(ShoppingCartCreated @event)
    {
        this._id = @event.Id;
        this._customerId = @event.CustomerId;
    }
}

public class ShoppingCartCreated : IDomainEvent
{
    public ShoppingCartCreated(Guid id, Guid customerId)
    {
        this.Id = id;
        this.CustomerId = customerId;
    }

    public Guid Id { get; private set; }
    public Guid CustomerID { get; private set; }
}

0

ঠিক আছে, প্রথম ইভেন্টটি এমন হওয়া উচিত যে কোনও গ্রাহক একটি শপিং কার্ট তৈরি করে , তাই যখন শপিং কার্টটি তৈরি করা হবে তখনই ইভেন্টের অংশ হিসাবে আপনার ইতিমধ্যে একটি গ্রাহক আইডি রয়েছে।

কোনও রাষ্ট্র যদি দুটি ভিন্ন ইভেন্টের মধ্যে থাকে তবে সংজ্ঞা অনুসারে এটি একটি বৈধ রাষ্ট্র। সুতরাং আপনি যদি বলেন যে কোনও বৈধ শপিং কার্ট কোনও গ্রাহকের সাথে সম্পর্কিত, এর অর্থ হ'ল কার্টটি তৈরি করার সময় আপনার কাছে গ্রাহকের তথ্য থাকা দরকার


আমার প্রশ্নটি কীভাবে ডোমেনটিকে মডেল করবেন তা নয়; আমি ইচ্ছাকৃতভাবে একটি প্রশ্ন জিজ্ঞাসার স্বার্থে একটি সাধারণ (তবে সম্ভবত অসম্পূর্ণ) ডোমেন মডেলটি ব্যবহার করছি। CreatedEmptyShoppingCartআমার প্রশ্নে ইভেন্টটি একবার দেখুন : আপনার পরামর্শ অনুসারে এটিতে গ্রাহক সম্পর্কিত তথ্য রয়েছে। আমার প্রশ্ন ShoppingCartবাস্তবায়নের সময় শ্রেণি নির্মাতার সাথে এই জাতীয় ইভেন্ট কীভাবে সম্পর্কিত বা প্রতিযোগিতা করে সে সম্পর্কে আরও about
stakx

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

0

দ্রষ্টব্য: আপনি যদি সামগ্রিক মূল ব্যবহার করতে না চান তবে "সত্তা" লেনদেনের সীমানা সম্পর্কে উদ্বেগের দিকে এগিয়ে যাওয়ার সময় আপনি এখানে যা জিজ্ঞাসা করছেন তার বেশিরভাগ অংশকেই অন্তর্ভুক্ত করে।

এটি সম্পর্কে চিন্তাভাবনার অন্য উপায়: একটি সত্তা হ'ল পরিচয় + রাষ্ট্র। একটি মান হিসাবে পৃথক, একটি সত্তা একই ব্যক্তি যখন তার রাষ্ট্র পরিবর্তন হয়।

তবে রাষ্ট্রটি নিজেই একটি মান বস্তু হিসাবে ভাবা যেতে পারে। এর অর্থ আমার, রাজ্য অপরিবর্তনীয়; সত্তার ইতিহাস হ'ল এক অপরিবর্তনীয় অবস্থা থেকে পরের দিকে রূপান্তর - প্রতিটি সংক্রমণ ইভেন্টের স্ট্রিমের একটি ঘটনার সাথে মিলে যায়।

State nextState = currentState.onEvent(e);

অন-এভেন্ট () পদ্ধতিটি অবশ্যই একটি ক্যোয়ারী - অবশ্যই বর্তমান স্টেটটি কোনওভাবেই পরিবর্তিত হয়নি, পরিবর্তে বর্তমান স্টেট স্টেটটি পরবর্তী স্টেট তৈরি করতে ব্যবহৃত আর্গুমেন্টগুলি গণনা করছে।

এই মডেলটি অনুসরণ করে, শপিং কার্টের সমস্ত দৃষ্টান্ত একই বীজমূল্য থেকে শুরু করে ভাবা যেতে পারে ....

State currentState = ShoppingCart.SEED;
for (Event e : history) {
    currentState = currentState.onEvent(e);
}

ShoppingCart cart = new ShoppingCart(id, currentState);

উদ্বেগের বিচ্ছেদ - শপিংকার্ট পরবর্তী কোন ইভেন্টটি হওয়া উচিত তা নির্ধারণের জন্য একটি কমান্ড প্রক্রিয়া করে; শপিংকার্ট স্টেট জানে কীভাবে পরবর্তী রাজ্যে উঠতে হয়।

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