نمط التصميم (نمط التصميم) عبارة عن مجموعة من الملخصات المبوبة والمفهرسة لتجربة تصميم التعليمات البرمجية التي يتم استخدامها بشكل متكرر، والمعروفة لدى معظم الأشخاص.
تنقسم أنماط التصميم إلى ثلاثة أنواع، بإجمالي 23 نوعًا:
مكتوب بالإشارة إلى مقالات في Hongyang، وNovice Tutorials، وما إلى ذلك. يرجى تصحيح لي إذا كان هناك أي أخطاء إذا كان هناك أي مخالفة، يرجى الاتصال بي لحذفها.
1. نمط التصميم نمط المراقب (نمط المراقب) أخذ خدمة WeChat العامة كمثال
2. نمط التصميم نمط المصنع (نمط المصنع) يبدأ ببيع روجيامو
3. نمط التصميم المفرد نمط التصميم (نمط المفرد) التحليل الكامل
4. نمط التصميم يأخذ نمط الإستراتيجية (نمط الإستراتيجية) ألعاب الأدوار كخلفية
5. نمط التصميم نمط المحول (نمط المحول) خذ شاحن الهاتف المحمول كمثال
6. تصميم نمط الأوامر Pattern لإدارة الأجهزة المنزلية الذكية
7. نمط التصميم الديكوري يعيدك إلى العالم الأسطوري
8. وضع التصميم، وضع المظهر (نمط الواجهة)، وضع الفيلم بنقرة واحدة
9. يُظهر نمط قالب نمط التصميم يوم المبرمج
10. نمط حالة التصميم (نمط الحالة) خذ آلة البيع كمثال
11. نمط التصميم Builder Pattern (نمط البناء) خذ بناء سيارة وشراء سيارة كمثال
12. نمط التصميم النموذجي (نمط النموذج الأولي) خذ الحصول على أشكال متعددة كمثال
13. نمط التصميم نمط وزن الذبابة (Flyweight Pattern) يأخذ عشوائياً الحصول على أشكال متعددة كمثال
14. نمط التصميم Proxy Pattern (نمط الوكيل) خذ الحصول على الصور من القرص كمثال
15. نمط التصميم Bridge Pattern (نمط الجسر) خذ دوائر الرسم بألوان مختلفة كمثال
16. تصميم نمط الجمع (النمط المركب) خذ إنشاء وطباعة التسلسل الهرمي للموظفين كمثال
17. نمط التصميم Iterator Pattern (Iterator Pattern) خذ استخدام المكرر لطباعة الأسماء كمثال
18. نمط التصميم Mediater Pattern (نمط الوسيط) أخذ غرف الدردشة العامة كمثال
19. نمط التصميم Memento Pattern (نمط Memento) خذ استخدام التذكار كمثال
20. نمط التصميم Interpreter Pattern (نمط المترجم) خذ شرح الجملة كمثال
21. نمط التصميم سلسلة نمط المسؤولية (سلسلة نمط المسؤولية) خذ سجلات الطباعة في Android Studio كمثال
22. نمط التصميم Visitor Pattern (نمط الزائر) خذ عرض مكونات الكمبيوتر كمثال
- المراقب
- مصنع
- سينجلتون
- الإستراتيجية
- محول
- يأمر
- ديكور
- الواجهة
- طريقة القالب
- ولاية
- منشئ
- النموذج الأولي
- وزن الذبابة
- الوكيل
- كوبري
- مركب
- مكرر
- الوسيط
- تذكار
- سلسلة المسؤولية
- زائر
يحدد تبعيات واحد إلى متعدد بين الكائنات، بحيث عندما يتغير كائن، سيتم إخطار جميع تبعياته وتحديثها تلقائيًا.
هناك العديد من الأماكن في JDK أو Andorid التي تنفذ نمط المراقب، مثل XXXView.addXXXListenter بالطبع، XXXView.setOnXXXListener ليس بالضرورة نمط المراقب، لأن نمط المراقب هو علاقة رأس بأطراف، وبالنسبة لـ setXXXListener، إنه زوج واحد، ويجب أن تسمى العلاقة بين 1 و1 رد اتصال.
واجهة خاصة: Subject.java؛
/**
* 注册一个观察者
*/
public void registerObserver ( Observer observer );
/**
* 移除一个观察者
*/
public void removeObserver ( Observer observer );
/**
* 通知所有观察者
*/
public void notifyObservers ();
فئة التنفيذ لحساب الخدمة ثلاثية الأبعاد: ObjectFor3D.java
@ Override
public void registerObserver ( Observer observer ) {
observers . add ( observer );
}
@ Override
public void removeObserver ( Observer observer ) {
int index = observers . indexOf ( observer );
if ( index >= 0 ) {
observers . remove ( index );
}
}
@ Override
public void notifyObservers () {
for ( Observer observer : observers ) {
observer . update ( msg );
}
}
/**
* 主题更新信息
*/
public void setMsg ( String msg ) {
this . msg = msg ;
notifyObservers ();
}
يحتاج جميع المراقبين إلى تنفيذ هذه الواجهة: Observer.java
public ObserverUser1 ( Subject subject ) {
subject . registerObserver ( this );
}
@ Override
public void update ( String msg ) {
Log . e ( "-----ObserverUser1 " , "得到 3D 号码:" + msg + ", 我要记下来。" );
}
الاختبار النهائي: ObserverActivity.java
// 创建服务号
objectFor3D = new ObjectFor3D ();
// 创建两个订阅者
observerUser1 = new ObserverUser1 ( objectFor3D );
observerUser2 = new ObserverUser2 ( objectFor3D );
// 两个观察者,发送两条信息
objectFor3D . setMsg ( "201610121 的3D号为:127" );
objectFor3D . setMsg ( "20161022 的3D号为:000" );
دعونا نذكر بإيجاز عائلة هذا النمط:
1. وضع المصنع الثابت
2. وضع المصنع البسيط (شراء Roujiamo من المتجر)
public RoujiaMo creatRoujiaMo ( String type ) {
RoujiaMo roujiaMo = null ;
switch ( type ) {
case "Suan" :
roujiaMo = new ZSuanRoujiaMo ();
break ;
case "La" :
roujiaMo = new ZLaRoujiaMo ();
break ;
case "Tian" :
roujiaMo = new ZTianRoujiaMo ();
break ;
default : // 默认为酸肉夹馍
roujiaMo = new ZSuanRoujiaMo ();
break ;
}
return roujiaMo ;
}
3. نموذج طريقة المصنع (فتح فرع)
يوفر أساليب مجردة لإنشاء Roujia MoStore: RoujiaMoStore.java
public abstract RoujiaMo sellRoujiaMo ( String type );
التنفيذ المحدد للطريقة المجردة: XianRoujiaMoStore.java
لا يزال الفرع يستخدم نموذج المصنع البسيط: XianSimpleRoujiaMoFactory.java
4. نمط المصنع المجرد (باستخدام المواد الخام الرسمية)
/**
* 准备工作
*/
public void prepare ( RoujiaMoYLFactory roujiaMoYLFactory ) {
Meet meet = roujiaMoYLFactory . creatMeet ();
YuanLiao yuanLiao = roujiaMoYLFactory . creatYuanLiao ();
Log . e ( "---RoujiaMo:" , "使用官方的原料 ---" + name + ": 揉面-剁肉-完成准备工作 yuanLiao:" + meet + "yuanLiao:" + yuanLiao );
}
يهدف الوضع الفردي بشكل أساسي إلى تجنب إهدار الموارد الناتج عن إنشاء مثيلات متعددة، ويمكن أن تؤدي المثيلات المتعددة بسهولة إلى نتائج غير صحيحة بسبب الاستدعاءات المتعددة. يمكن أن يضمن استخدام الوضع الفردي وجود مثيل واحد فقط في التطبيق بأكمله .
التعريف: هناك حاجة إلى ثلاث خطوات فقط لضمان تفرد الكائن
مقارنة التعريف:
أسلوب هان الجائع [متوفر]: SingletonEHan.java
يحتوي على نمط هان البطيء [يوصى بقفل التحقق المزدوج]: SingletonLanHan.java
private SingletonLanHan () {}
private static SingletonLanHan singletonLanHanFour ;
public static SingletonLanHan getSingletonLanHanFour () {
if ( singletonLanHanFour == null ) {
synchronized ( SingletonLanHan . class ) {
if ( singletonLanHanFour == null ) {
singletonLanHanFour = new SingletonLanHan ();
}
}
}
return singletonLanHanFour ;
}
نمط الإستراتيجية: يحدد مجموعة من الخوارزميات ويغلفها بشكل منفصل لجعلها قابلة للتبادل. يسمح هذا النمط بأن تكون تغييرات الخوارزميات مستقلة عن العملاء الذين يستخدمون الخوارزميات.
RoleA roleA = new RoleA ( "---A" );
roleA . setiDisplayBehavior ( new DisplayYZ ())
. setiAttackBehavior ( new AttackXL ())
. setiDefendBehavior ( new DefendTMS ())
. setiRunBehavior ( new RunJCTQ ());
roleA . display (); // 样子
roleA . attack (); // 攻击
roleA . run (); // 逃跑
roleA . defend (); // 防御
التعريف: تحويل واجهة الفئة إلى واجهة أخرى يتوقعها العميل، ويسمح المحول للفئات ذات الواجهات غير المتوافقة بالتعاون مع بعضها البعض. هذا التعريف مقبول، حيث أن وظيفة المحول هي تحويل واجهة واحدة إلى واجهة أخرى.
خذ الشاحن كمثال: يبلغ جهد شواحن الهاتف المحمول بشكل عام حوالي 5 فولت. يبلغ جهد التيار المتردد المنزلي في الصين 220 فولت، لذا يتطلب شحن الهاتف المحمول محولًا (مخفض الجهد).
الهاتف المحمول: Mobile.java
يعتمد الهاتف على واجهة توفر جهد 5 فولت وهي V5Power.java
ما لدينا هو 220 فولت تيار متردد منزلي: V220Power.java
محول لإكمال وظيفة تحويل 220 فولت إلى 5 فولت : V5PowerAdapter.java
الاختبار النهائي: شحن الهاتف:
Mobile mobile = new Mobile ();
V5Power v5Power = new V5PowerAdapter ( new V200Power ());
mobile . inputPower ( v5Power );
التعريف: قم بتغليف "الطلبات" في كائنات بحيث يمكن تحديد معلمات الكائنات الأخرى باستخدام طلبات أو قوائم انتظار أو سجلات مختلفة. يدعم وضع الأوامر أيضًا العمليات غير القابلة للإلغاء. (التبسيط: قم بتغليف الطلب في كائن وفصل طالب الإجراء ومنفذ الإجراء.)
QuickCommand quickCloseCommand = new QuickCommand ( new Command []{ new LightOffCommand ( light ), new ComputerOffCommand ( computer ), new DoorCloseCommand ( door )});
controlPanel . setCommands ( 6 , quickOpenCommand );
controlPanel . keyPressed ( 6 );
controlPanel . setCommands ( 0 , new DoorOpenCommand ( door )); // 开门
controlPanel . keyPressed ( 0 );
نمط الديكور: لتوسيع الوظائف، توفر أدوات الديكور بديلاً أكثر مرونة للتكامل، وربط المسؤوليات بالكائنات ديناميكيًا.
دعونا نوضح بإيجاز أين يأتي دور نمط الديكور عندما نقوم بتصميم فئة، نحتاج إلى إضافة بعض الوظائف المساعدة إلى هذه الفئة، ولا نريد تغيير رمز هذه الفئة، وهذا هو الوقت الذي يأتي فيه نمط الديكور حان الوقت. وهذا يعكس أيضًا مبدأ: يجب أن تكون الفئات مفتوحة للامتدادات ومغلقة أمام التعديلات.
المتطلبات: تصميم نظام المعدات الخاص باللعبة. المتطلب الأساسي هو أن تكون قادرًا على حساب قوة الهجوم ووصف كل جهاز بعد دمجه مع العديد من الأحجار الكريمة:
1. فئة المعدات الفائقة: IEquip.java
2. فئات التنفيذ لكل جهاز:
3. فئة ممتازة من الزخارف (الزخارف تنتمي أيضًا إلى المعدات): IEquipDecorator.java
4. تنفيذ صنف الزخارف :
5. الاختبار النهائي: حساب قوة الهجوم وعرض الوصف:
Log . e ( "---" , "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: " );
IEquip iEquip = new RedGemDecorator ( new RedGemDecorator ( new BlueGemDecorator ( new ShoeEquip ())));
Log . e ( "---" , "攻击力:" + iEquip . caculateAttack ());
Log . e ( "---" , "描述语:" + iEquip . description ());
التعريف: توفير واجهة موحدة للوصول إلى مجموعة من الواجهات في النظام الفرعي. يحدد المظهر واجهة عالية المستوى لتسهيل استخدام النظام الفرعي. في الواقع، من أجل راحة العملاء، يتم تغليف مجموعة من العمليات في طريقة.
الطلب: أفضل مشاهدة الأفلام، لذلك اشتريت جهاز عرض وجهاز كمبيوتر وستيريو، وصممت إضاءة الغرفة، واشتريت آلة صنع الفشار، ثم عندما أرغب في مشاهدة فيلم، أحتاج إلى المشاهدة بنقرة واحدة وإيقاف التشغيل بنقرة واحدة .
التبديل والعمليات الأخرى لكل فئة جهاز:
على سبيل المثال: آلة الفشار: PopcornPopper.java
فئة السينما: HomeTheaterFacade.java
/**
* 一键观影
*/
public void watchMovie () {
computer . on ();
light . down ();
popcornPopper . on ();
popcornPopper . makePopcorn ();
projector . on ();
projector . open ();
player . on ();
player . make3DListener ();
}
الاختبار النهائي: مشاهدة الفيلم بنقرة واحدة:
new HomeTheaterFacade ( computer , light , player , popcornPopper , projector ). watchMovie ();
التعريف: يحدد الهيكل العظمي للخوارزمية ويؤجل بعض الخطوات إلى الفئات الفرعية. تسمح طريقة القالب للفئات الفرعية بإعادة تعريف خطوات الخوارزمية دون تغيير بنية الخوارزمية.
المتطلبات: وصف موجز: شركتنا لديها مبرمجون، ومختبرون، وموارد بشرية، ومديرو مشاريع، وما إلى ذلك. يتم استخدام وضع طريقة القالب أدناه لتسجيل حالة العمل لجميع الموظفين.
ثلاثة أنواع من الأدوار في نمط أسلوب القالب
1. الطريقة الملموسة
2. الطريقة المجردة
3. طريقة الخطاف
الطبقة الفائقة للعامل: Worker.java
// 具体方法
public final void workOneDay () {
Log . e ( "workOneDay" , "-----------------work start----------------" );
enterCompany ();
work ();
exitCompany ();
Log . e ( "workOneDay" , "-----------------work end----------------" );
}
// 工作 抽象方法
public abstract void work ();
// 钩子方法
public boolean isNeedPrintDate () {
return false ;
}
private void exitCompany () {
if ( isNeedPrintDate ()) {
Log . e ( "exitCompany" , "---" + new Date (). toLocaleString () + "--->" );
}
Log . e ( "exitCompany" , name + "---离开公司" );
}
فئة تنفيذ المبرمج (يمكن معرفة الوقت): ITWorker.java
/**
* 重写父类的此方法,使可以查看离开公司时间
*/
@ Override
public boolean isNeedPrintDate () {
return true ;
}
الاختبار النهائي:
انظر كيف يعمل الجميع:
QAWorker qaWorker = new QAWorker ( "测试人员" );
qaWorker ();
HRWorker hrWorker = new HRWorker ( "莉莉姐" );
hrWorker . workOneDay ();
...
التحقق من وقت مغادرة المبرمج للشركة:
ITWorker itWorker = new ITWorker ( "jingbin" );
itWorker . workOneDay ();
التعريف: يسمح للكائن بتغيير سلوكه عندما تتغير حالته الداخلية، مما يجعل الكائن يبدو كما لو أنه قام بتعديل فئته.
أصبح التعريف غامضًا مرة أخرى. عندما تتغير الحالة الداخلية لكائن ما، يتغير سلوكه مع تغير الحالة.
المتطلبات: خذ آلة البيع كمثال (هناك حالات مثل إدخال العملة المعدنية وعدم إدخال العملة المعدنية، وطرق إدخال العملة المعدنية وإرجاعها)
سيتم تحسين التنفيذ الأولي لآلة البيع: VendingMachine.java
آلة بيع محسنة (أكثر مرونة): VendingMachineBetter.java
// 放钱
public void insertMoney () {
currentState . insertMoney ();
}
// 退钱
public void backMoney () {
currentState . backMoney ();
}
// 转动曲柄
public void turnCrank () {
currentState . turnCrank ();
if ( currentState == soldState || currentState == winnerState ) {
currentState . dispense (); //两种情况会出货
}
}
// 出商品
public void dispense () {
Log . e ( "VendingMachineBetter" , "---发出一件商品" );
if ( count > 0 ) {
count --;
}
}
// 设置对应状态
public void setState ( State state ) {
this . currentState = state ;
}
واجهة الحالة: State.java
فئة تنفيذ الواجهة المقابلة للحالة:
تحسين اختبار آلة البيع:
// 初始化售货机,且里面有3个商品
VendingMachineBetter machineBetter = new VendingMachineBetter ( 3 );
machineBetter . insertMoney ();
machineBetter . turnCrank ();
وضع البناء هو وضع إنشاء الكائن. يمكن لوضع الإنشاء فصل التمثيل الداخلي للمنتج عن عملية إنتاج المنتج، بحيث يمكن لعملية الإنشاء إنشاء كائنات منتج ذات تمثيلات داخلية مختلفة.
المتطلبات: يذهب المستخدمون إلى متجر سيارات لشراء سيارة.
التحليل: يقوم متجر السيارات باستخراج السيارات المقابلة حسب احتياجات كل مستخدم
منشئ الطبقة الفائقة: منشئ
public abstract class Builder {
public abstract void setPart ( String name , String type );
public abstract Product getProduct ();
}
فئة التنفيذ المقابلة للمنشئ: ConcreteBuilder
public class ConcreteBuilder extends Builder {
private Product product = new Product ();
@ Override
public void setPart ( String name , String type ) {
product . setName ( name );
product . setType ( type );
}
@ Override
public Product getProduct () {
return product ;
}
}
مدير المتجر يلتقط السيارة:
// 店长
Director director = new Director ();
// 得到宝马汽车,内部实现提取宝马汽车的详情操作
Product product = director . getBProduct ();
// 展示汽车信息
product . showProduct ();
يتم استخدام نمط النموذج الأولي لإنشاء كائنات متكررة مع ضمان الأداء. هذا النوع من أنماط التصميم هو نمط إبداعي يوفر طريقة مثالية لإنشاء الكائنات.
يطبق هذا النمط واجهة النموذج الأولي التي يتم استخدامها لإنشاء نسخة من الكائن الحالي. يتم استخدام هذا الوضع عندما تكون تكلفة إنشاء الكائنات مباشرة مرتفعة نسبيًا. على سبيل المثال، يجب إنشاء كائن بعد عملية قاعدة بيانات مكلفة. يمكننا تخزين الكائن مؤقتًا، وإرجاع نسخة منه عند الطلب التالي، وتحديث قاعدة البيانات عند الحاجة لتقليل استدعاءات قاعدة البيانات.
بأخذ الحصول على أشكال متعددة كمثال، هناك أربع خطوات:
1. قم بإنشاء فئة مجردة تنفذ الواجهة القابلة للاستنساخ. الشكل (التطبيقات القابلة للاستنساخ)
public abstract class Shape implements Cloneable {
private String id ;
protected String type ;
public abstract void draw ();
public String getId () {
return id ;
}
public void setId ( String id ) {
this . id = id ;
}
@ Override
public Object clone () {
Object object = null ;
try {
object = super . clone ();
} catch ( CloneNotSupportedException e ) {
Log . e ( "--" , e . getMessage ());
}
return object ;
}
}
2. قم بإنشاء فئة كيان تعمل على توسيع الفئة المجردة أعلاه. دائرة، مستطيل، مربع
public class Circle extends Shape {
public Circle () {
type = "Circle" ;
}
@ Override
public void draw () {
Log . e ( "---" , "Inside Circle::draw() method." );
}
}
3. قم بإنشاء فصل للحصول على فئات الكيانات من قاعدة البيانات وتخزينها في Hashtable. ShapeCache
public class ShapeCache {
private static Hashtable < String , Shape > shapeMap = new Hashtable < String , Shape >();
public static Shape getShape ( String shapeId ) {
Shape shapeCache = shapeMap . get ( shapeId );
return ( Shape ) shapeCache . clone ();
}
// 对每种形状都运行数据库查询,并创建该形状
// shapeMap.put(shapeKey, shape);
// 例如,我们要添加三种形状
public static void loadCache () {
Circle circle = new Circle ();
circle . setId ( "1" );
shapeMap . put ( circle . getId (), circle );
Rectangle rectangle = new Rectangle ();
rectangle . setId ( "2" );
shapeMap . put ( rectangle . getId (), rectangle );
Square square = new Square ();
square . setId ( "3" );
shapeMap . put ( square . getId (), square );
}
}
4. استخدم فئة ShapeCache للحصول على نسخة من الشكل المخزن في Hashtable.
// 使用 ShapeCache 类来获取存储在 Hashtable 中的形状的克隆。
ShapeCache . loadCache ();
Shape shapeCache1 = ShapeCache . getShape ( "1" );
Shape shapeCache2 = ShapeCache . getShape ( "2" );
Shape shapeCache3 = ShapeCache . getShape ( "3" );
يستخدم بشكل أساسي لتقليل عدد الكائنات التي تم إنشاؤها لتقليل استخدام الذاكرة وتحسين الأداء. هذا النوع من أنماط التصميم هو نمط هيكلي يوفر طريقة لتقليل عدد الكائنات وبالتالي تحسين بنية الكائن التي يتطلبها التطبيق.
يحاول نمط وزن الذبابة إعادة استخدام الكائنات الموجودة من نفس النوع، أو إنشاء كائنات جديدة في حالة عدم العثور على كائن مطابق. سنوضح هذا النمط من خلال إنشاء 5 كائنات ترسم 20 دائرة في مواقع مختلفة. نظرًا لوجود 5 ألوان فقط، يتم استخدام خاصية اللون للتحقق من كائن الدائرة الموجود.
بأخذ أشكال متعددة بشكل عشوائي كمثال، هناك أربع خطوات:
1. قم بإنشاء واجهة.
public interface Shape {
void draw ();
}
2. قم بإنشاء فئة كيان تقوم بتنفيذ الواجهة.
public class Circle implements Shape {
private String color ;
private int x ;
private int y ;
private int radius ;
public Circle ( String color ) {
this . color = color ;
}
public void setX ( int x ) {
this . x = x ;
}
public void setY ( int y ) {
this . y = y ;
}
public void setRadius ( int radius ) {
this . radius = radius ;
}
@ Override
public void draw () {
Log . e ( "---" , "Circle: Draw() [Color : " + color
+ ", x : " + x + ", y :" + y + ", radius :" + radius );
}
}
3. قم بإنشاء مصنع لإنشاء كائنات فئات الكيانات بناءً على معلومات معينة.
public class ShapeFactory {
private static final HashMap < String , Shape > circleMap = new HashMap < String , Shape >();
public static Shape getShape ( String color ) {
Shape shape = circleMap . get ( color );
if ( shape == null ) {
shape = new Circle ( color );
circleMap . put ( color , shape );
Log . e ( "getShape" , "Creating circle of color : " + color );
}
return shape ;
}
}
4. استخدم هذا المصنع للحصول على كائن فئة الكيان عن طريق تمرير معلومات اللون.
for ( int i = 0 ; i < 20 ; i ++) {
Circle circle = ( Circle ) ShapeFactory . getShape ( getRandomColor ());
circle . setX ( getRandomX ());
circle . setY ( getRandomY ());
circle . setRadius ( 100 );
circle . draw ();
}
تمثل إحدى الفئات وظيفة فئة أخرى. في نمط الوكيل، نقوم بإنشاء كائنات مع كائنات موجودة من أجل توفير واجهة وظيفية للعالم الخارجي. يمكن أن نفهم أنه إذا لم يكن هناك مثل هذا الكائن في الذاكرة، فسيتم إنشاؤه، وإذا كان هناك، فسيتم إرجاع الكائن مباشرة.
بأخذ الحصول على الصور من القرص كمثال، هناك ثلاث خطوات إجمالاً:
1. قم بإنشاء واجهة.
public interface Image {
void display ();
}
2. قم بإنشاء فئة كيان RealImage التي تنفذ الواجهة. فئة الوكيل المقابلة: ProxyImage.
public class RealImage implements Image {
private String fileName ;
public RealImage ( String fileName ) {
this . fileName = fileName ;
loadFromDisk ( fileName );
}
private void loadFromDisk ( String fileName ) {
Log . e ( "RealImage" , "loading " + fileName );
}
@ Override
public void display () {
Log . e ( "RealImage" , "Displaying " + fileName );
}
}
public class ProxyImage implements Image {
private String fileName ;
private RealImage realImage ;
public ProxyImage ( String fileName ) {
this . fileName = fileName ;
}
@ Override
public void display () {
if ( realImage == null ) {
realImage = new RealImage ( fileName );
}
realImage . display ();
}
}
3. عند الطلب، استخدم ProxyImage للحصول على كائن من فئة RealImage.
Image image = new ProxyImage ( "test_10mb.png" );
// 第一次是new的,图像从磁盘加载
image . display ();
// 第二次取缓存,图像不需要从磁盘加载
image . display ();
يتم استخدام Bridge لفصل التجريد والتنفيذ بحيث يمكن أن يتغير الاثنان بشكل مستقل. هذا النوع من أنماط التصميم هو نمط هيكلي، يفصل بين التجريد والتنفيذ من خلال توفير بنية جسرية بينهما.
بأخذ دوائر الرسم بألوان مختلفة كمثال، ينقسم التنفيذ إلى خمس خطوات:
1. إنشاء واجهة تنفيذ الجسر.
public interface DrawAPI {
void drawCircle ( int radius , int x , int y );
}
2. قم بإنشاء فئة تنفيذ جسر الكيان التي تنفذ واجهة DrawAPI. الدائرة الحمراء، الدائرة الخضراء
public class RedCircle implements DrawAPI {
@ Override
public void drawCircle ( int radius , int x , int y ) {
Log . e ( "---" , "Drawing Circle[ color: red, radius: "
+ radius + ", x: " + x + ", " + y + "]" );
}
}
3. استخدم واجهة DrawAPI لإنشاء شكل الفصل الملخص.
public abstract class Shape {
protected DrawAPI drawAPI ;
protected Shape ( DrawAPI drawAPI ) {
this . drawAPI = drawAPI ;
}
public abstract void draw ();
}
4. قم بإنشاء فئة كيان تقوم بتنفيذ واجهة الشكل.
public class Circle extends Shape {
private int x , y , radius ;
protected Circle ( int x , int y , int radius , DrawAPI drawAPI ) {
super ( drawAPI );
this . x = x ;
this . y = y ;
this . radius = radius ;
}
@ Override
public void draw () {
drawAPI . drawCircle ( radius , x , y );
}
}
5. استخدم فئتي Shape وDrawAPI لرسم دوائر بألوان مختلفة.
// 画红圆
Circle circle = new Circle ( 10 , 10 , 100 , new RedCircle ()); s
circle . draw ();
// 画绿圆
Circle circle2 = new Circle ( 20 , 20 , 100 , new GreenCircle ());
circle2 . draw ();
يُطلق عليه أيضًا نمط الجزء-الكل، ويتم استخدامه للتعامل مع مجموعة من الكائنات المتشابهة ككائن واحد. يجمع وضع التركيب الكائنات وفقًا لبنية الشجرة، والتي تُستخدم لتمثيل التسلسل الهرمي الجزئي والكامل. هذا النوع من أنماط التصميم هو نمط هيكلي، يقوم بإنشاء بنية شجرية لمجموعات من الكائنات.
خذ إنشاء وطباعة التسلسل الهرمي للموظفين كمثال، مثال الوحدة الأصغر:
1. قم بإنشاء فئة الموظف بقائمة كائنات الموظف.
public class Employee {
private String name ;
// 部门
private String dept ;
// 工资
private int salary ;
// 员工 list
private List < Employee > subordinates ;
public Employee ( String name , String dept , int salary ) {
this . name = name ;
this . dept = dept ;
this . salary = salary ;
this . subordinates = new ArrayList < Employee >();
}
public void add ( Employee e ) {
subordinates . add ( e );
}
public void remove ( Employee e ) {
subordinates . remove ( e );
}
public List < Employee > getSubordinates () {
return subordinates ;
}
@ Override
public String toString () {
return "Employee{" +
"name='" + name + ''' +
", dept='" + dept + ''' +
", salary=" + salary +
", subordinates=" + subordinates +
'}' ;
}
}
2. استخدم فئة الموظف لإنشاء وطباعة التسلسل الهرمي للموظفين.
final Employee ceo = new Employee ( "John" , "CEO" , 30000 );
Employee headSales = new Employee ( "Robert" , "Head sales" , 20000 );
Employee headMarketing = new Employee ( "Michel" , "Head Marketing" , 20000 );
Employee clerk1 = new Employee ( "Laura" , "Marketing" , 10000 );
Employee clerk2 = new Employee ( "Bob" , "Marketing" , 10000 );
Employee salesExecutive1 = new Employee ( "Richard" , "Sales" , 10000 );
Employee salesExecutive2 = new Employee ( "Rob" , "Sales" , 10000 );
ceo . add ( headSales );
ceo . add ( headMarketing );
headSales . add ( salesExecutive1 );
headSales . add ( salesExecutive2 );
headMarketing . add ( clerk1 );
headMarketing . add ( clerk2 );
Log . e ( "---" , ceo . toString ());
// 打印
/*
* Employee{name='John', dept='CEO', salary=30000,
* subordinates=[Employee{name='Robert', dept='Head sales', salary=20000,
* subordinates=[
* Employee{name='Richard', dept='Sales', salary=10000, subordinates=[]},
* Employee{name='Rob', dept='Sales', salary=10000, subordinates=[]}]},
* Employee{name='Michel', dept='Head Marketing', salary=20000,
* subordinates=[Employee{name='Laura', dept='Marketing', salary=10000, subordinates=[]},
* Employee{name='Bob', dept='Marketing', salary=10000, subordinates=[]}]}]}
*/
نمط تصميم شائع جدًا في بيئات برمجة Java و.Net. يُستخدم هذا النمط للوصول إلى عناصر كائن المجموعة بشكل تسلسلي دون معرفة التمثيل الأساسي لكائن المجموعة. نمط التكرار هو نمط سلوكي.
بأخذ استخدام المكرر لطباعة الأسماء كمثال، هناك ثلاث خطوات إجمالاً:
1. إنشاء واجهة:
public interface Iterator {
public boolean hasNext ();
public Object next ();
}
public interface Container {
public Iterator getIterator ();
}
2. قم بإنشاء فئة كيان تقوم بتنفيذ واجهة الحاوية. تحتوي هذه الفئة على فئة داخلية NameIterator تقوم بتنفيذ واجهة Iterator.
public class NameRepository implements Container {
private String names [] = { "John" , "jingbin" , "youlookwhat" , "lookthis" };
@ Override
public Iterator getIterator () {
return new NameIterator ();
}
private class NameIterator implements Iterator {
int index ;
@ Override
public boolean hasNext () {
if ( index < names . length ) {
return true ;
}
return false ;
}
@ Override
public Object next () {
if ( hasNext ()) {
return names [ index ++];
}
return null ;
}
}
}
3. استخدم NameRepository للحصول على المكرر وطباعة الاسم.
NameRepository nameRepository = new NameRepository ();
for ( Iterator iterator = nameRepository . getIterator (); iterator . hasNext (); ) {
String name = ( String ) iterator . next ();
Log . e ( "---" , name );
/*
* /---: John
* /---: jingbin
* /---: youlookwhat
* /---: lookthis
*/
}
يستخدم لتقليل تعقيد الاتصال بين الكائنات والفئات المتعددة. يوفر هذا النمط فئة وسيطة تتعامل عادةً مع الاتصال بين الفئات المختلفة وتدعم الاقتران غير المحكم، مما يسهل صيانة التعليمات البرمجية. نموذج الوسيط هو نموذج سلوكي.
إذا أخذنا غرفة محادثة عامة كمثال، فإن الحد الأدنى من الخطوات النموذجية للوحدة هي:
1. قم بإنشاء فئة وسيطة.
public class CharRoom {
public static void showMessage ( User user , String message ) {
Log . e ( "---" , new Date (). toString ()
+ " [" + user . getName () + "] : " + message );
}
}
2. قم بإنشاء فئة المستخدم.
public class User {
private String name ;
public User ( String name ) {
this . name = name ;
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
public void sendMessage ( String message ) {
// 使用中介类
CharRoom . showMessage ( this , message );
}
}
3. استخدم كائن المستخدم لعرض الاتصال بينهما.
User jingbin = new User ( "jingbin" );
jingbin . sendMessage ( "Hi~ youlookwhat!" );
//---: Sun Feb 02 08:11:47 GMT+00:00 2020 [jingbin] : Hi~ youlookwhat!
User jingbin = new User ( "youlookwhat" );
jingbin . sendMessage ( "Hi~ jingbin!" );
//---: Sun Feb 02 08:11:49 GMT+00:00 2020 [youlookwhat] : Hi~ jingbin!
حفظ حالة معينة للكائن بحيث يمكن استعادتها في الوقت المناسب. وضع المذكرة هو الوضع السلوكي.
باستخدام المذكرة كمثال، فإن الحد الأدنى لخطوات الوحدة هي:
1. قم بإنشاء فئة Memento.
public class Memento {
private String state ;
public Memento ( String state ) {
this . state = state ;
}
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
}
2. قم بإنشاء فئة المنشئ.
public class Originator {
private String state ;
public String getState () {
return state ;
}
public void setState ( String state ) {
this . state = state ;
}
public Memento setSateToMemento () {
return new Memento ( state );
}
public String getStateFromMemento ( Memento memento ) {
return memento . getState ();
}
}
3. قم بإنشاء فئة CareTaker.
public class CareTaker {
private List < Memento > mementoList = new ArrayList < Memento >();
public void add ( Memento memento ) {
mementoList . add ( memento );
}
public Memento get ( int index ) {
return mementoList . get ( index );
}
}
4. استخدم كائنات CareTaker وOrigator.
// 管理者
CareTaker careTaker = new CareTaker ();
Originator originator = new Originator ();
originator . setState ( "State #1" );
originator . setState ( "State #2" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #3" );
// 保存状态
careTaker . add ( originator . setSateToMemento ());
originator . setState ( "State #4" );
Log . e ( "---" , "Current State: " + originator . getState ());
// 得到保存的状态
String fromMemento1 = originator . getStateFromMemento ( careTaker . get ( 0 ));
Log . e ( "---" , "First Saved State: " + fromMemento1 );
String fromMemento2 = originator . getStateFromMemento ( careTaker . get ( 1 ));
Log . e ( "---" , "Second Saved State: " + fromMemento2 );
/*
* /---: Current State: State #4
* /---: First Saved State: State #2
* /---: Second Saved State: State #3
*/
يوفر طريقة لتقييم بناء الجملة أو تعبيرات اللغة وهو نمط سلوكي. يطبق هذا النمط واجهة تعبير تفسر سياقًا محددًا. يُستخدم هذا الوضع في تحليل SQL ومحركات معالجة الرموز وما إلى ذلك.
خذ شرح جملة كمثال، الحد الأدنى من خطوات الوحدة:
1. إنشاء واجهة التعبير التعبير.
public interface Expression {
public boolean interpreter ( String content );
}
2. قم بإنشاء فئة كيان تنفذ الواجهة المذكورة أعلاه. TerminalExpression، OrExpression، AndExpression.
public class TerminalExpression implements Expression {
private String data ;
public TerminalExpression ( String data ) {
this . data = data ;
}
@ Override
public boolean interpreter ( String content ) {
// 是包含判断
return content . contains ( data );
}
}
public class OrExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public OrExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) || expression2 . interpreter ( content );
}
}
public class AndExpression implements Expression {
private Expression expression1 ;
private Expression expression2 ;
public AndExpression ( Expression expression1 , Expression expression2 ) {
this . expression1 = expression1 ;
this . expression2 = expression2 ;
}
@ Override
public boolean interpreter ( String content ) {
return expression1 . interpreter ( content ) && expression2 . interpreter ( content );
}
}
3. استخدم فئة التعبير لإنشاء القواعد وتحليلها.
/**
* 规则:jingbin 和 youlookwhat 是男性
*/
public static Expression getMaleExpression () {
TerminalExpression jingbin = new TerminalExpression ( "jingbin" );
TerminalExpression youlookwhat = new TerminalExpression ( "youlookwhat" );
return new OrExpression ( jingbin , youlookwhat );
}
/**
* 规则:Julie 是一个已婚的女性
*/
public static Expression getMarriedWomanExpression () {
TerminalExpression julie = new TerminalExpression ( "Julie" );
TerminalExpression married = new TerminalExpression ( "Married" );
return new AndExpression ( julie , married );
}
Expression maleExpression = getMaleExpression ();
// jingbin is male: true
Log . e ( "---" , "jingbin is male: " + maleExpression . interpreter ( "jingbin" ));
Expression womanExpression = getMarriedWomanExpression ();
// Julie is married woman: true
Log . e ( "---" , "Julie is married woman: " + womanExpression . interpreter ( "Married Julie" ));
يقوم نمط سلسلة المسؤولية بإنشاء سلسلة من كائنات المستلمين للطلب. يقوم هذا النمط بفصل مرسل الطلب ومتلقيه بناءً على نوع الطلب. هذا النوع من أنماط التصميم هو نمط سلوكي. في هذا النمط، عادةً ما يحتوي كل جهاز استقبال على إشارة إلى جهاز استقبال آخر. إذا لم يتمكن الكائن من التعامل مع الطلب، فإنه يمرر نفس الطلب إلى المستلم التالي، وهكذا.
بأخذ سجلات الطباعة في Android Studio كمثال، الحد الأدنى لخطوات الوحدة هو:
1. قم بإنشاء فئة مسجل مجردة AbstractLogger.
public abstract class AbstractLogger {
public static int INFO = 1 ;
public static int DEBUG = 2 ;
public static int ERROR = 3 ;
protected int level ;
// 责任链中的下一个元素
protected AbstractLogger nextLogger ;
public void setNextLogger ( AbstractLogger nextLogger ) {
this . nextLogger = nextLogger ;
}
public void logMessage ( int level , String message ) {
if ( this . level <= level ) {
write ( message );
}
// 递归效果,不断调用下一级 logMessage
if ( nextLogger != null ) {
nextLogger . logMessage ( level , message );
}
}
protected abstract void write ( String message );
}
2. قم بإنشاء فئة كيان تعمل على توسيع فئة المسجل.
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Standard Console::Logger " + message );
}
}
public class FileLogger extends AbstractLogger {
public FileLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "File::Logger " + message );
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger ( int level ) {
this . level = level ;
}
@ Override
protected void write ( String message ) {
Log . e ( "---" , "Error Console::Logger " + message );
}
}
3. إنشاء أنواع مختلفة من قطع الأشجار. امنحهم مستويات خطأ مختلفة وقم بتعيين المسجل التالي داخل كل مسجل. يمثل المسجل التالي في كل مسجل جزءًا من السلسلة.
public static AbstractLogger getChainOfLoggers () {
ErrorLogger errorLogger = new ErrorLogger ( AbstractLogger . ERROR );
FileLogger fileLogger = new FileLogger ( AbstractLogger . DEBUG );
ConsoleLogger consoleLogger = new ConsoleLogger ( AbstractLogger . INFO );
errorLogger . setNextLogger ( fileLogger );
fileLogger . setNextLogger ( consoleLogger );
return errorLogger ;
}
AbstractLogger logger = getChainOfLoggers ();
// ---: Standard Console::Logger this is an information.
logger . logMessage ( AbstractLogger . INFO , "this is an information." );
// ---: File::Logger this is a debug level information.
// ---: Standard Console::Logger this is a debug level information.
logger . logMessage ( AbstractLogger . DEBUG , "this is a debug level information." );
// ---: Error Console::Logger this is a error level information.
// ---: File::Logger this is a error level information.
// ---: Standard Console::Logger this is a error level information.
logger . logMessage ( AbstractLogger . ERROR , "this is a error level information." );
في نمط الزائر، نستخدم فئة الزائر، والتي تغير خوارزمية التنفيذ لفئة العنصر. بهذه الطريقة، يمكن أن تتغير خوارزمية تنفيذ العنصر مع تغير الزائر. هذا النوع من أنماط التصميم هو نمط سلوكي. وفقًا للمخطط، يقبل كائن العنصر كائنًا زائرًا حتى يتمكن كائن الزائر من التعامل مع العمليات على كائن العنصر.
وبأخذ مكونات جهاز العرض كمثال، يتم تنفيذه بشكل أساسي في خمس خطوات:
1. تحديد الواجهة التي تمثل العنصر.
public interface ComputerPart {
public void accept ( ComputerPartVisitor computerPartVisitor );
}
2. قم بإنشاء فئة كيان تعمل على توسيع الفئة المذكورة أعلاه. لوحة المفاتيح، الشاشة، الماوس، الكمبيوتر
public class Computer implements ComputerPart {
private ComputerPart [] parts ;
public Computer () {
this . parts = new ComputerPart []{ new Mouse (), new Keyboard (), new Monitor ()};
}
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
for ( ComputerPart part : parts ) {
part . accept ( computerPartVisitor );
}
computerPartVisitor . visit ( this );
}
}
public class Mouse implements ComputerPart {
@ Override
public void accept ( ComputerPartVisitor computerPartVisitor ) {
computerPartVisitor . visit ( this );
}
}
3. تحديد الواجهة التي تمثل الزوار.
public interface ComputerPartVisitor {
public void visit ( Computer computer );
public void visit ( Mouse mouse );
public void visit ( Keyboard keyboard );
public void visit ( Monitor monitor );
}
4. قم بإنشاء زائر كيان يقوم بتنفيذ الفئة أعلاه.
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@ Override
public void visit ( Computer computer ) {
Log . e ( "---" , "Displaying Computer." );
}
@ Override
public void visit ( Mouse mouse ) {
Log . e ( "---" , "Displaying Mouse." );
}
@ Override
public void visit ( Keyboard keyboard ) {
Log . e ( "---" , "Displaying Keyboard." );
}
@ Override
public void visit ( Monitor monitor ) {
Log . e ( "---" , "Displaying Monitor." );
}
}
5. استخدم ComputerPartDisplayVisitor لعرض مكونات الكمبيوتر.
ComputerPart computer = new Computer ();
computer . accept ( new ComputerPartDisplayVisitor ());
/*
*打印:
*---: Displaying Mouse.
*---: Displaying Keyboard.
*---: Displaying Monitor.
*---: Displaying Computer.
*/