تدعم العديد من اللغات الحديثة مطابقة الأنماط على مستوى اللغة. لا تدعم Java حاليًا مطابقة الأنماط ، ولكن هناك أمل في أن تتغير الأشياء في المستقبل.
المقارنة مع العينة تكشف للمطور القدرة على كتابة التعليمات البرمجية بشكل أكثر مرونة وجمالا ، مع تركها مفهومة.
باستخدام إمكانيات Java 8 ، يمكنك تطبيق بعض ميزات مطابقة الأنماط في شكل مكتبة. في هذه الحالة ، يمكنك استخدام كل من العبارة والتعبير.
نمط ثابت يسمح التحقق من المساواة مع الثوابت. في Java ، يسمح لك المحول بالتحقق من وجود أرقام متساوية وتعدادات وسلاسل. لكن في بعض الأحيان أريد التحقق من مساواة ثوابت الكائنات باستخدام طريقة يساوي ().
switch (data) { case new Person("man") -> System.out.println("man"); case new Person("woman") -> System.out.println("woman"); case new Person("child") -> System.out.println("child"); case null -> System.out.println("Null value "); default -> System.out.println("Default value: " + data); };
بالنسبة لخيارات التفرع المختلفة ، تحتاج إلى استخدام الأحمال الزائدة لطريقة التطابق (). لذلك ، في الوقت الحالي ، تدعم المكتبة القدرة على التحقق من قيم المتغير بستة ثوابت.
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.ConstantPattern.matches; matches(data, new Person("man"), () -> System.out.println("man"); new Person("woman"), () -> System.out.println("woman"); new Person("child"), () -> System.out.println("child"); Null.class, () -> System.out.println("Null value "), Else.class, () -> System.out.println("Default value: " + data) );
يتيح لك نمط Tuple التحقق من مساواة العديد من التغييرات مع الثوابت في وقت واحد.
switch (side, width) { case "top", 25 -> System.out.println("top"); case "bottom", 30 -> System.out.println("bottom"); case "left", 15 -> System.out.println("left"); case "right", 15 -> System.out.println("right"); case null -> System.out.println("Null value "); default -> System.out.println("Default value "); };
في الوقت الحالي ، تدعم المكتبة القدرة على تحديد 4 متغيرات و 6 فروع.
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.TuplePattern.matches; matches(side, width, "top", 25, () -> System.out.println("top"); "bottom", 30, () -> System.out.println("bottom"); "left", 15, () -> System.out.println("left"); "right", 15, () -> System.out.println("right"); Null.class, () -> System.out.println("Null value"), Else.class, () -> System.out.println("Default value") );
يسمح لك نمط اختبار الكتابة بالمطابقة في نفس الوقت مع النوع واستخراج قيمة المتغير. في Java ، لهذا نحتاج أولاً إلى التحقق من الكتابة ، والضغط على النوع ثم تعيينه لمتغير جديد.
switch (data) { case Integer i -> System.out.println(i * i); case Byte b -> System.out.println(b * b); case Long l -> System.out.println(l * l); case String s -> System.out.println(s * s); case null -> System.out.println("Null value "); default -> System.out.println("Default value: " + data); };
في الوقت الحالي ، تدعم المكتبة القدرة على التحقق من قيم المتغير بستة أنواع.
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.VerifyPattern.matches; matches(data, Integer.class, i -> { System.out.println(i * i); }, Byte.class, b -> { System.out.println(b * b); }, Long.class, l -> { System.out.println(l * l); }, String.class, s -> { System.out.println(s * s); }, Null.class, () -> { System.out.println("Null value "); }, Else.class, () -> { System.out.println("Default value: " + data); } );
يتيح لك نمط الحماية إمكانية مطابقة النوع في وقت واحد والتحقق من الظروف.
switch (data) { case Integer i && i != 0 -> System.out.println(i * i); case Byte b && b > -1 -> System.out.println(b * b); case Long l && l < 5 -> System.out.println(l * l); case String s && !s.empty() -> System.out.println(s * s); case null -> System.out.println("Null value "); default -> System.out.println("Default: " + data); };
في الوقت الحالي ، تدعم المكتبة القدرة على التحقق من قيم المتغير مع 6 أنواع وشروط.
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.GuardPattern.matches; matches(data, Integer.class, i -> i != 0, i -> { System.out.println(i * i); }, Byte.class, b -> b > -1, b -> { System.out.println(b * b); }, Long.class, l -> l == 5, l -> { System.out.println(l * l); }, Null.class, () -> { System.out.println("Null value "); }, Else.class, () -> { System.out.println("Default value: " + data); } );
لتبسيط كتابة الشرط ، يمكن للمطور استخدام الوظائف التالية للمقارنة: أقل / لتر ، أكبرثان / gt ، أقلثانأورق / لو ، أكبرثانأوركوال / ge ،
يساوي / مكافئ ، notEqual / ne. ومن أجل حذف الشروط ، يمكنك تجربة: دائمًا / نعم ، أبدًا / لا.
matches(data, Integer.class, ne(0), i -> { System.out.println(i * i); }, Byte.class, gt(-1), b -> { System.out.println(b * b); }, Long.class, eq(5), l -> { System.out.println(l * l); }, Null.class, () -> { System.out.println("Null value "); }, Else.class, () -> { System.out.println("Default value: " + data); } );
يتيح لك نمط التفكيك مطابقة النوع وتحلل الكائن إلى مكونات في وقت واحد. في Java ، لهذا نحتاج أولاً إلى التحقق من الكتابة ، والاطلاع على نوع ما ، وتعيينه لمتغير جديد ، وعندئذٍ فقط الوصول إلى حقول الفصل الدراسي عبر الحروف.
let (int w, int h) = figure; switch (figure) { case Rectangle(int w, int h) -> out.println("square: " + (w * h)); case Circle(int r) -> out.println("square: " + (2 * Math.PI * r)); default -> out.println("Default square: " + 0); }; for ((int w, int h) : listFigures) { System.out.println("square: " + (w * h)); }
في الوقت الحالي ، تدعم المكتبة القدرة على التحقق من قيم المتغير بثلاثة أنواع وتحلل الكائن إلى 3 مكونات.
import org.kl.state.Else; import static org.kl.pattern.DeconstructPattern.matches; import static org.kl.pattern.DeconstructPattern.foreach; import static org.kl.pattern.DeconstructPattern.let; Figure figure = new Rectangle(); let(figure, (int w, int h) -> { System.out.println("border: " + w + " " + h)); }); matches(figure, Rectangle.class, (int w, int h) -> out.println("square: " + (w * h)), Circle.class, (int r) -> out.println("square: " + (2 * Math.PI * r)), Else.class, () -> out.println("Default square: " + 0) ); foreach(listRectangles, (int w, int h) -> { System.out.println("square: " + (w * h)); });
علاوة على ذلك ، من أجل الحصول على مكون ، يجب أن يكون للفصل طريقة أو أكثر من طرق التفكيك. يجب تسمية هذه الطرق باستخدام " استخراج التعليقات التوضيحية".
يجب أن تكون جميع المعلمات مفتوحة. نظرًا لأنه لا يمكن نقل العناصر الأولية إلى طريقة بالرجوع إليها ، فأنت بحاجة إلى استخدام أدوات الالتفاف للأدوات الأولية IntRef و FloatRef ، إلخ.
import org.kl.type.IntRef; ... @Extract public void deconstruct(IntRef width, IntRef height) { width.set(this.width); height.set(this.height); }
باستخدام Java 11 أيضًا ، يمكنك استنتاج أنواع من معلمات تفكيك.
Figure figure = new Rectangle(); let(figure, (var w, var h) -> { System.out.println("border: " + w + " " + h)); }); matches(figure, Rectangle.class, (var w, var h) -> out.println("square: " + (w * h)), Circle.class, (var r) -> out.println("square: " + (2 * Math.PI * r)), Else.class, () -> out.println("Default square: " + 0) ); foreach(listRectangles, (var w, var h) -> { System.out.println("square: " + (w * h)); });
يتيح لك نمط الخاصية مطابقة النوع والوصول إلى حقول الفصل بأسمائهم في وقت واحد. بدلاً من توفير جميع الحقول ، يمكنك الوصول إلى الحقول التي تحتاج إليها بأي ترتيب.
let (w: int w, h:int h) = figure; switch (figure) { case Rect(w: int w == 5, h: int h == 10) -> out.println("sqr: " + (w * h)); case Rect(w: int w == 10, h: int h == 15) -> out.println("sqr: " + (w * h)); case Circle (r: int r) -> out.println("sqr: " + (2 * Math.PI * r)); default -> out.println("Default sqr: " + 0); }; for ((w: int w, h: int h) : listRectangles) { System.out.println("square: " + (w * h)); }
في الوقت الحالي ، تدعم المكتبة القدرة على التحقق من قيم المتغير بثلاثة أنواع وتحلل الكائن إلى 3 مكونات.
import org.kl.state.Else; import static org.kl.pattern.PropertyPattern.matches; import static org.kl.pattern.PropertyPattern.foreach; import static org.kl.pattern.PropertyPattern.let; import static org.kl.pattern.PropertyPattern.of; Figure figure = new Rectangle(); let(figure, of("w", "h"), (int w, int h) -> { System.out.println("border: " + w + " " + h)); }); matches(figure, Rect.class, of("w", 5, "h", 10), (int w, int h) -> out.println("sqr: " + (w * h)), Rect.class, of("w", 10, "h", 15), (int w, int h) -> out.println("sqr: " + (w * h)), Circle.class, of("r"), (int r) -> out.println("sqr: " + (2 * Math.PI * r)), Else.class, () -> out.println("Default sqr: " + 0) ); foreach(listRectangles, of("x", "y"), (int w, int h) -> { System.out.println("square: " + (w * h)); });
يمكنك أيضًا استخدام طريقة أخرى لتبسيط حقول التسمية.
Figure figure = new Rect(); let(figure, Rect::w, Rect::h, (int w, int h) -> { System.out.println("border: " + w + " " + h)); }); matches(figure, Rect.class, Rect::w, Rect::h, (int w, int h) -> out.println("sqr: " + (w * h)), Circle.class, Circle::r, (int r) -> out.println("sqr: " + (2 * Math.PI * r)), Else.class, () -> System.out.println("Default sqr: " + 0) ); foreach(listRectangles, Rect::w, Rect::h, (int w, int h) -> { System.out.println("square: " + (w * h)); });
يتيح لك نمط الموضع إمكانية مطابقة النوع في وقت واحد والتحقق من قيمة الحقول في ترتيب الإعلان. في Java ، لهذا نحتاج أولاً إلى التحقق من النوع ، وإلقائه على نوع ، وتعيينه لمتغير جديد ، وعندئذٍ فقط الوصول إلى حقول الفصل عبر getters والتحقق من المساواة.
switch (data) { case Circle(5) -> System.out.println("small circle"); case Circle(15) -> System.out.println("middle circle"); case null -> System.out.println("Null value "); default -> System.out.println("Default value: " + data); };
في الوقت الحالي ، تدعم المكتبة القدرة على التحقق من قيم المتغير بستة أنواع والتحقق من 4 حقول في آن واحد.
import org.kl.state.Else; import org.kl.state.Null; import static org.kl.pattern.PositionPattern.matches; import static org.kl.pattern.PositionPattern.of; matches(data, Circle.class, of(5), () -> { System.out.println("small circle"); }, Circle.class, of(15), () -> { System.out.println("middle circle"); }, Null.class, () -> { System.out.println("Null value "); }, Else.class, () -> { System.out.println("Default value: " + data); } );
أيضًا ، إذا لم يرغب المطور في التحقق من بعض الحقول ، فيجب وضع علامة على هذه الحقول بتعليقات توضيحية @. يجب الإعلان عن هذه الحقول أخيرًا.
class Circle { private int radius; @Exclude private int temp; }
يسمح لك النمط الثابت بمطابقة النوع وفك الكائن في وقت واحد باستخدام أساليب المصنع.
Optional some = ...; switch (some) { case Optional.empty() -> System.out.println("empty value"); case Optional.of(var v) -> System.out.println("value: " + v); default -> System.out.println("Default value"); };
في الوقت الحالي ، تدعم المكتبة القدرة على التحقق من قيم المتغير بستة أنواع وتقسيم الكائن إلى 3 مكونات.
import org.kl.state.Else; import static org.kl.pattern.StaticPattern.matches; import static org.kl.pattern.StaticPattern.of; Optional some = ...; matches(figure, Optinal.class, of("empty"), () -> System.out.println("empty value"), Optinal.class, of("of") , (var v) -> System.out.println("value: " + v), Else.class, () -> System.out.println("Default value") );
في الوقت نفسه ، للحصول على المكون ، يجب أن يكون لدى الفصل طريقة أو أكثر من طرق التفكيك ، وهي عبارة عن استخراج التعليقات التوضيحية.
@Extract public void of(IntRef value) { value.set(this.value); }
يسهل نمط التسلسل معالجة تسلسل البيانات.
List<Integer> list = ...; switch (list) { case Ranges.head(var h) -> System.out.println("list head: " + h); case Ranges.tail(var t) -> System.out.println("list tail: " + t); case Ranges.empty() -> System.out.println("Empty value"); default -> System.out.println("Default value"); };
باستخدام المكتبة ، يمكنك الكتابة على النحو التالي.
import org.kl.state.Else; import org.kl.range.Ranges; import static org.kl.pattern.SequencePattern.matches; List<Integer> list = ...; matches(figure, Ranges.head(), (var h) -> System.out.println("list head: " + h), Ranges.tail(), (var t) -> System.out.println("list tail: " + t), Ranges.empty() () -> System.out.println("Empty value"), Else.class, () -> System.out.println("Default value") );
أيضا ، لتبسيط التعليمات البرمجية ، يمكنك استخدام الوظائف التالية.
import static org.kl.pattern.CommonPattern.with; import static org.kl.pattern.CommonPattern.when; Rectangle rect = new Rectangle(); with(rect, it -> { it.setWidth(5); it.setHeight(10); }); when( side == Side.LEFT, () -> System.out.println("left value"), side == Side.RIGHT, () -> System.out.println("right value") );
كما ترون مطابقة الأنماط هي أداة قوية تجعل شفرة الكتابة أسهل بكثير. باستخدام تعبيرات lambda ، ومراجع الطريقة واشتقاق أنواع معلمات lambda ، يمكنك محاكاة إمكانيات مطابقة الأنماط باستخدام وسائل اللغة ذاتها.
شفرة المصدر للمكتبة مفتوحة ومتاحة على جيثب .