বিহেভিয়ার আমাদের সুযোগ দেয় একটি বিহেভিয়ার মডিউলে ইন্টারফেস (ফাংশন ও ম্যাক্রোর সেট) ডিফাইন করার, যা পরে ভিন্ন ভিন্ন কলব্যাক মডিউল দিয়ে ইমপ্লিমেন্ট করা যায়। শেয়ার করা এই ইন্টারফেসের সুবাদে ওই কলব্যাক মডিউলগুলোকে একে অন্যের জায়গায় ব্যবহার করা যায়।
লক্ষ্য করুন, "behaviours" শব্দটির বানানটি ব্রিটিশ ইংরেজি অনুযায়ী লেখা হয়েছে।
একটি বিহেভিয়ার ডিফাইন করতে হলে আমাদের একটি নতুন মডিউল তৈরি করতে হবে এবং কাঙ্ক্ষিত ইন্টারফেসের অংশ এমন ফাংশনগুলোর একটি তালিকা উল্লেখ করতে হবে। প্রতিটি ফাংশন @callback মডিউল অ্যাট্রিবিউট ব্যবহার করে ডিফাইন করতে হবে। এর সিনট্যাক্স একটি ফাংশন টাইপস্পেক-এর (@spec) মতোই। আমাদের একটি ফাংশনের নাম, আর্গুমেন্টের টাইপগুলোর একটি তালিকা এবং সম্ভাব্য সব রিটার্ন টাইপ উল্লেখ করতে হবে।
defmodule Countable do
@callback count(collection :: any) :: pos_integer
end
আমাদের মডিউলে একটি বিদ্যমান বিহেভিয়ার যোগ করতে (অর্থাৎ একটি কলব্যাক মডিউল তৈরি করতে) আমরা @behaviour মডিউল অ্যাট্রিবিউট ব্যবহার করি। এর মান হওয়া উচিত যে বিহেভিয়ার মডিউলটি আমরা যোগ করছি তার নাম।
এরপর আমাদের ওই বিহেভিয়ার মডিউলের প্রয়োজনীয় সব ফাংশন (কলব্যাক) ডিফাইন করতে হবে। আমরা যদি অন্য কারও লেখা বিহেভিয়ার ইমপ্লিমেন্ট করি, যেমন Elixir-এর বিল্ট-ইন Access বা GenServer বিহেভিয়ার, তাহলে hexdocs.pm-এর ডকুমেন্টেশনে ওই বিহেভিয়ারের সব কলব্যাকের তালিকা পাব।
একটি কলব্যাক মডিউল কেবল তার বিহেভিয়ারের অংশ এমন ফাংশনগুলো ইমপ্লিমেন্ট করেই সীমাবদ্ধ নয়। একটি মডিউল একাধিক বিহেভিয়ারও ইমপ্লিমেন্ট করতে পারে।
কোন ফাংশন কোন বিহেভিয়ার থেকে এসেছে তা বোঝাতে আমরা প্রতিটি ফাংশনের আগে @impl মডিউল অ্যাট্রিবিউট ব্যবহার করব। এর মান হওয়া উচিত যে বিহেভিয়ার মডিউলটি এই কলব্যাকটি ডিফাইন করেছে তার নাম।
defmodule BookCollection do
@behaviour Countable
defstruct [:list, :owner]
@impl Countable
def count(collection) do
Enum.count(collection.list)
end
def mark_as_read(collection, book) do
# other function unrelated to the Countable behaviour
end
end
বিহেভিয়ার ডিফাইন করার সময় একটি কলব্যাকের ডিফল্ট ইমপ্লিমেন্টেশন দেওয়া সম্ভব। এই ইমপ্লিমেন্টেশনটি __using__/1 ম্যাক্রোর কোটেড এক্সপ্রেশনে ডিফাইন করা উচিত। বিহেভিয়ার মডিউলের ব্যবহারকারীরা যাতে ডিফল্ট ইমপ্লিমেন্টেশনটি ওভাররাইড করতে পারেন, সেজন্য ফাংশন ইমপ্লিমেন্টেশনের পরে defoverridable/1 ম্যাক্রোটি কল করুন। এটি কী (key) হিসেবে ফাংশনের নাম আর মান হিসেবে ফাংশনের অ্যারিটি নিয়ে একটি কিওয়ার্ড লিস্ট নেয়।
defmodule Countable do
@callback count(collection :: any) :: pos_integer
defmacro __using__(_) do
quote do
@behaviour Countable
def count(collection), do: Enum.count(collection)
defoverridable count: 1
end
end
end
মনে রাখবেন, ডিফল্ট কলব্যাক ইমপ্লিমেন্টেশন ডিফাইন করা ছাড়া অন্য কোনো উদ্দেশ্যে __using__/1-এর ভেতরে ফাংশন ডিফাইন করা নিরুৎসাহিত, তবে আপনি সবসময় অন্য একটি মডিউলে ফাংশন ডিফাইন করে সেগুলো __using__/1 ম্যাক্রোতে ইমপোর্ট করতে পারেন।