کار با Spring boot و drools -بخش 1
ابتدا چند نمونه از شرط هایی که می توانیم در بخش when فایل های قوانین قرار دهیم را با هم می بینیم. شرط های مختلف را با کاما از هم جدا می کنیم. در شرط ها امکان اضافه نمودن fact های مختلف نیز هست.
هر زمان که شی CartItem ساخته شد و مقدار فیلد cartStatus (که یک enum است) برابر PROCESSED بود و مقدار فیلد qty در شی CartItem نیز از مقدار فیلد availableQty در fact محصول( product) بیشتر بود وارد بخش then شود .
when $cartItem : CartItem(cartStatus != CartStatus.PROCESSED, qty > product.getAvailableQty()) then..
امکان فراخوانی متدی از یک fact که خروجی اش مقدار true/false باشد نیز مانند بالا وجود دارد.
when $cartItem : CartItem(cartStatus != CartStatus.PROCESSED, product.isRequiresRegisteration(), !cart.customer.isRegistered(product)) then... when $cartItem : CartItem(cartStatus != CartStatus.PROCESSED, cart.customer.isNew()) then ...
امکان بررسی مقدار type های string با == و pattern.
when $cartItem : CartItem(cartStatus != CartStatus.PROCESSED, cart.customer.coupon == 'DISC01') then... when Product(code != 0 && code not matches "^[0-9]{6}$") then..
زمانیکه شرطی دارید که ممکن است در تعداد زیادی قانون لحاظ شود،کافی ایست یک قانون تعریف کنید و در سایر قوانین از آن استفاده نمایید.
در مثال زیر ما تمام افرادی که در دپارتمان it قرار دارند و مدیر هستند را می خواهیم. ابتدا یک کلاس ITManager تعریف می کنیم که یک فیلد از جنس Employee دارد.
public class ITManager {
private Employee emp;
public ITManager(Employee emp){
this.emp=emp;} //getter and setter }
تعریف قانون: درصورتی که کارمند مدیر بود و در بخش it نیز قرار داشت به Rule Engine اضافه می کنیم.
rule "IT Manager Inference" when
$dept: Department(name=="IT");
$emp: Employee(dept == $dept,manager==true);
then insert(new ITManager($emp)); end
نحوه ی استفاده از قانون تعریف شده در سایر قوانین:
rule "give Manager Laptop" when $emp: Employee(); $itManager: ITManager(emp == $emp); then $emp.setMessage("Give Laptop"); System.out.println($emp.getName()+ ": "+$emp.getDept().getName()+ ":"+$emp.getMessage()); end
اگر شرط ITManager درست باشد وارد then شده و متن مورد نظر را چاپ می کند.
نکته:
در فایل قوانین نیز مثل کلاس های جاوایی امکان اضافه نمودن comment را نیز دارید.comment های یک خطی با # یا // ، و چند خطی نیز با /*..*/.
جدول تصمیم گیری:
اکسل بالا شامل بخش های مختلف زیر است.
بخش RuleSet :مسیری در پروژه است که فایل اکسل قوانین در آن قرار دارد.باید اولین مقدار در فایل اکسل باشد.
بخش Sequential:مقدار true,false را می گیرد اگر True باشد قوانین را بر اساس بالاترین اولویت تا پایین اجرا میکند. اجباری نمی باشد.
بخش Import: تمام جاوا کلاس های مورد نیاز و با کاما از هم جدا می شوند.
بخشVariables: متغیر های global در این بخش تعریف می شود.
بخشFunctions: می تواند یک یا چند Functions بر اساس بیزینس قوانین داشته باشد.
بخش Notes: توضیح کلی در مورد هدف و کار اکسل
ستون های CONDITION و ACTION : دراولین ردیف این ستون یک reference به factهامون قرار می دهیم و در ردیف های بعدی با کمک آن reference به value هاشون(متغییرهاشون) دسترسی داریم. در اکسل بالا اگر سن مشتری برابر 1 بود میزان تخفیف 15 درصد در نظر گرفته می شود، در غیر این صورت 25 درصد.
مراحل ایجاد پروژه در Springboot:
وابستگی های مورد نیاز برای ساخت پروژه را در pom فایل اضافه می کنیم:(در صورتیکه می خواهید از جداول تصمیم گیری استفاده نمایید drools-decisiontables را اضافه نمایید.)
<dependency> <groupId>org.kie</groupId> <artifactId>kie-ci</artifactId> <version>7.31.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-decisiontables</artifactId> <version>7.1.0.Beta1</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>7.31.0.Final</version> </dependency>
کلاس محصول به همراه enum مورد نیاز:
public class Product { private String type; private int code; private int discount; //getter/setter/ constructor ...... } public enum TypeEnum { DIAMOND("diamond"), GOLD("gold"); ..... }
خواندن فایل های قوانین که مسیرش را در زیر مشخص کرده ایم و ساخت container
ایجاد session مورد نظر و فعال(fire) کردن تمام قوانین موجود در container.
دو نوع session وجود دارد: Stateless Sessionو Stateful Session که متانسب با نیاز و نوع پروژه از آن ها استفاده می کنیم . در صورت استفاده از Stateful Session باید حتما متد dispose را صدا کنیم تا فضای گرفته شده را آزاد کند مانند زیر:
تست پروژه: با ایجاد یک کلاس کنترلر، بر اساس ورودی ها امکان اجرا شدن حداقل یک قانون وجود دارد.
فایل قانون در زیر مسیر :src/main/resources/rules(حتی امکان throw کردن خطا را نیز داریم)
package rules import com.isc.mcb.model.Product import com.isc.mcb.model.TypeEnum import com.isc.mcb.NumberFormatException rule "Offer for Diamond" when $productObject: Product(TypeEnum.DIAMOND.type.equals(type)) then $productObject.setDiscount(15); end rule "Offer for Gold" when $productObject: Product(TypeEnum.GOLD.type.equals(type)) then $productObject.setDiscount(25); end rule "CodeValidation" when Product(code != 0 && code not matches "^[0-9]{6}$") then throw new NumberFormatException("Invalid Product Code. Must be a valid 6 digits number."); end
بر اساس این که fact ها نوعش چی باشد، درصد آن مشخص می شود و اگر طول کد محصول بیشتر از 6 رقم باشد خطا برگردانده می شود.
برای دیدن مثال های بیشتر در فایل قوانین نیز به آدرس example سر بزنید.