138
									
								
								zh/adapter/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								zh/adapter/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,138 @@ | |||||||
|  | --- | ||||||
|  | layout: pattern | ||||||
|  | title: Adapter | ||||||
|  | folder: adapter | ||||||
|  | permalink: /patterns/adapter/ | ||||||
|  | categories: Structural | ||||||
|  | tags: | ||||||
|  |  - Gang of Four | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | ## 又被称为 | ||||||
|  | 包装器 | ||||||
|  |  | ||||||
|  | ## 目的 | ||||||
|  | 将一个接口转换成另一个客户所期望的接口。适配器让那些本来因为接口不兼容的类可以合作无间。 | ||||||
|  |  | ||||||
|  | ## 解释 | ||||||
|  |  | ||||||
|  | 现实世界例子 | ||||||
|  |  | ||||||
|  | > 考虑有这么一种情况,在你的存储卡中有一些照片,你想将其传到你的电脑中。为了传送数据,你需要某种能够兼容你电脑接口的适配器以便你的储存卡能连上你的电脑。在这种情况下,读卡器就是一个适配器。 | ||||||
|  | > 另一个例子就是注明的电源适配器;三脚插头不能插在两脚插座上,需要一个电源适配器来使其能够插在两脚插座上。 | ||||||
|  | > 还有一个例子就是翻译官,他翻译一个人对另一个人说的话。 | ||||||
|  |  | ||||||
|  | 用直白的话来说 | ||||||
|  |  | ||||||
|  | > 适配器模式让你可以把不兼容的对象包在适配器中,以让其兼容其他类。 | ||||||
|  |  | ||||||
|  | 维基百科中说 | ||||||
|  |  | ||||||
|  | > 在软件工程中,适配器模式是一种可以让现有类的接口把其作为其他接口来使用的设计模式。它经常用来使现有的类和其他类能够工作并且不用修改其他类的源代码。 | ||||||
|  |  | ||||||
|  | **编程样例(对象适配器)** | ||||||
|  |  | ||||||
|  | 假如有一个船长他只会划船,但不会航行。 | ||||||
|  |  | ||||||
|  | 首先我们有接口`RowingBoat`和`FishingBoat` | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  | public interface RowingBoat { | ||||||
|  |   void row(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class FishingBoat { | ||||||
|  |   private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class); | ||||||
|  |   public void sail() { | ||||||
|  |     LOGGER.info("The fishing boat is sailing"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 船长希望有一个`RowingBoat`接口的实现,这样就可以移动 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  | public class Captain { | ||||||
|  |  | ||||||
|  |   private final RowingBoat rowingBoat; | ||||||
|  |   // default constructor and setter for rowingBoat | ||||||
|  |   public Captain(RowingBoat rowingBoat) { | ||||||
|  |     this.rowingBoat = rowingBoat; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void row() { | ||||||
|  |     rowingBoat.row(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 现在海盗来了,我们的船长需要逃跑但是只有一个渔船可用。我们需要创建一个可以让船长使用其划船技能来操作渔船的适配器。 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  | public class FishingBoatAdapter implements RowingBoat { | ||||||
|  |  | ||||||
|  |   private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class); | ||||||
|  |  | ||||||
|  |   private final FishingBoat boat; | ||||||
|  |  | ||||||
|  |   public FishingBoatAdapter() { | ||||||
|  |     boat = new FishingBoat(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void row() { | ||||||
|  |     boat.sail(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 现在 `船长` 可以使用`FishingBoat`接口来逃离海盗了。 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  | var captain = new Captain(new FishingBoatAdapter()); | ||||||
|  | captain.row(); | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## 类图 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## 应用 | ||||||
|  | 使用适配器模式当 | ||||||
|  |  | ||||||
|  | * 你想使用一个已有类,但是它的接口不能和你需要的所匹配 | ||||||
|  | * 你需要创建一个可重用类,该类与不相关或不可预见的类进行协作,即不一定具有兼容接口的类 | ||||||
|  | * 你需要使用一些现有的子类,但是子类化他们每一个的子类来进行接口的适配是不现实的。一个对象适配器可以适配他们父类的接口。 | ||||||
|  | * 大多数使用第三方类库的应用使用适配器作为一个在应用和第三方类库间的中间层来使应用和类库解耦。如果必须使用另一个库,则只需使用一个新库的适配器而无需改变应用程序的代码。 | ||||||
|  |  | ||||||
|  | ## 后果: | ||||||
|  | 类和对象适配器有不同的权衡取舍。一个类适配器 | ||||||
|  |  | ||||||
|  | *	适配被适配者到目标接口,需要保证只有一个具体的被适配者类。作为结果,当我们想适配一个类和它所有的子类时,类适配器将不会起作用。 | ||||||
|  | *	可以让适配器重写一些被适配者的行为,因为适配器是被适配者的子类。 | ||||||
|  | *	只引入了一个对象,并且不需要其他指针间接访问被适配者。 | ||||||
|  |  | ||||||
|  | 对象适配器	 | ||||||
|  |  | ||||||
|  | *	一个适配器可以和许多被适配者工作,也就是被适配者自己和所有它的子类。适配器同时可以为所有被适配者添加功能。 | ||||||
|  | *	覆盖被适配者的行为变得更难。需要子类化被适配者然后让适配器引用这个子类不是被适配者。 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## 现实世界的案例 | ||||||
|  |  | ||||||
|  | * [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29) | ||||||
|  | * [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-) | ||||||
|  | * [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-) | ||||||
|  | * [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## 鸣谢 | ||||||
|  |  | ||||||
|  | * [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) | ||||||
|  | * [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) | ||||||
|  | * [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) | ||||||
|  | * [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ``` | ||||||
							
								
								
									
										159
									
								
								zh/observer/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								zh/observer/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | |||||||
|  | --- | ||||||
|  | layout: pattern | ||||||
|  | title: Observer | ||||||
|  | folder: observer | ||||||
|  | permalink: /patterns/observer/ | ||||||
|  | categories: Behavioral | ||||||
|  | tags: | ||||||
|  |  - Gang Of Four | ||||||
|  |  - Reactive | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | ## Also known as | ||||||
|  | ## 又被称为 | ||||||
|  |  | ||||||
|  | 家属,发布订阅模式 | ||||||
|  |  | ||||||
|  | ## 目的 | ||||||
|  |  | ||||||
|  | 定义一种一对多的对象依赖关系这样当一个对象改变状态时,所有依赖它的对象都将自动通知或更新。 | ||||||
|  |  | ||||||
|  | ## 解释 | ||||||
|  |  | ||||||
|  | 真实世界例子 | ||||||
|  |  | ||||||
|  | > 在遥远的土地上生活着霍比特人和兽人的种族。他们都是户外生活的人所以他们密切关注天气的变化。可以说他们不断地关注着天气。 | ||||||
|  |  | ||||||
|  | 通俗的说 | ||||||
|  |  | ||||||
|  | > 注册成为一个观察者以接收对象状态的改变。 | ||||||
|  |  | ||||||
|  | 维基百科说 | ||||||
|  |  | ||||||
|  | > 观察者模式是这样的一种软件设计模式:它有一个被称为主题的对象,维护着一个所有依赖于它的依赖者清单,也就是观察者清单,当主题的状态发生改变时,主题通常会调用观察者的方法来自动通知观察者们。 | ||||||
|  |  | ||||||
|  | **编程示例** | ||||||
|  |  | ||||||
|  | 让我们先来介绍天气观察者的接口以及我们的种族,兽人和霍比特人。 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  | public interface WeatherObserver { | ||||||
|  |  | ||||||
|  |   void update(WeatherType currentWeather); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class Orcs implements WeatherObserver { | ||||||
|  |  | ||||||
|  |   private static final Logger LOGGER = LoggerFactory.getLogger(Orcs.class); | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void update(WeatherType currentWeather) { | ||||||
|  |     LOGGER.info("The orcs are facing " + currentWeather.getDescription() + " weather now"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class Hobbits implements WeatherObserver { | ||||||
|  |  | ||||||
|  |   private static final Logger LOGGER = LoggerFactory.getLogger(Hobbits.class); | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void update(WeatherType currentWeather) { | ||||||
|  |     switch (currentWeather) { | ||||||
|  |       LOGGER.info("The hobbits are facing " + currentWeather.getDescription() + " weather now"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 然后这里是不断变化的天气。 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  | public class Weather { | ||||||
|  |  | ||||||
|  |   private static final Logger LOGGER = LoggerFactory.getLogger(Weather.class); | ||||||
|  |  | ||||||
|  |   private WeatherType currentWeather; | ||||||
|  |   private final List<WeatherObserver> observers; | ||||||
|  |  | ||||||
|  |   public Weather() { | ||||||
|  |     observers = new ArrayList<>(); | ||||||
|  |     currentWeather = WeatherType.SUNNY; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void addObserver(WeatherObserver obs) { | ||||||
|  |     observers.add(obs); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void removeObserver(WeatherObserver obs) { | ||||||
|  |     observers.remove(obs); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Makes time pass for weather. | ||||||
|  |    */ | ||||||
|  |   public void timePasses() { | ||||||
|  |     var enumValues = WeatherType.values(); | ||||||
|  |     currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length]; | ||||||
|  |     LOGGER.info("The weather changed to {}.", currentWeather); | ||||||
|  |     notifyObservers(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void notifyObservers() { | ||||||
|  |     for (var obs : observers) { | ||||||
|  |       obs.update(currentWeather); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 这是完整的示例。 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  |     var weather = new Weather(); | ||||||
|  |     weather.addObserver(new Orcs()); | ||||||
|  |     weather.addObserver(new Hobbits()); | ||||||
|  |  | ||||||
|  |     weather.timePasses(); | ||||||
|  |     // The weather changed to rainy. | ||||||
|  |     // The orcs are facing rainy weather now | ||||||
|  |     // The hobbits are facing rainy weather now | ||||||
|  |     weather.timePasses(); | ||||||
|  |     // The weather changed to windy. | ||||||
|  |     // The orcs are facing windy weather now | ||||||
|  |     // The hobbits are facing windy weather now | ||||||
|  |     weather.timePasses(); | ||||||
|  |     // The weather changed to cold. | ||||||
|  |     // The orcs are facing cold weather now | ||||||
|  |     // The hobbits are facing cold weather now | ||||||
|  |     weather.timePasses(); | ||||||
|  |     // The weather changed to sunny. | ||||||
|  |     // The orcs are facing sunny weather now | ||||||
|  |     // The hobbits are facing sunny weather now | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Class diagram | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## 应用 | ||||||
|  | 在下面任何一种情况下都可以使用观察者模式 | ||||||
|  |  | ||||||
|  | * 当抽象具有两个方面时,一个方面依赖于另一个方面。将这些方面封装在单独的对象中,可以使你分别进行更改和重用 | ||||||
|  | * 当一个对象的改变的同时需要改变其他对象,同时你又不知道有多少对象需要改变时 | ||||||
|  | * 当一个对象可以通知其他对象而无需假设这些对象是谁时。换句话说,你不想让这些对象紧耦合。 | ||||||
|  |  | ||||||
|  | ## 典型用例 | ||||||
|  |  | ||||||
|  | * 一个对象的改变导致其他对象的改变 | ||||||
|  |  | ||||||
|  | ## Java中的例子 | ||||||
|  |  | ||||||
|  | * [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html) | ||||||
|  | * [java.util.EventListener](http://docs.oracle.com/javase/8/docs/api/java/util/EventListener.html) | ||||||
|  | * [javax.servlet.http.HttpSessionBindingListener](http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSessionBindingListener.html) | ||||||
|  | * [RxJava](https://github.com/ReactiveX/RxJava) | ||||||
|  |  | ||||||
|  | ## 鸣谢 | ||||||
|  |  | ||||||
|  | * [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) | ||||||
|  | * [Java Generics and Collections](https://www.amazon.com/gp/product/0596527756/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596527756&linkCode=as2&tag=javadesignpat-20&linkId=246e5e2c26fe1c3ada6a70b15afcb195) | ||||||
|  | * [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) | ||||||
|  | * [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) | ||||||
							
								
								
									
										136
									
								
								zh/strategy/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								zh/strategy/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | |||||||
|  | --- | ||||||
|  | layout: pattern | ||||||
|  | title: Strategy | ||||||
|  | folder: strategy | ||||||
|  | permalink: /patterns/strategy/ | ||||||
|  | categories: Behavioral | ||||||
|  | tags: | ||||||
|  |  - Gang of Four | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | ## 又被称为 | ||||||
|  | 政策(方针)模式 | ||||||
|  |  | ||||||
|  | ## 目的 | ||||||
|  |  | ||||||
|  | 定义一个家族算法,并封装好其中每一个,使它们可以互相替换。策略模式使算法的变化独立于使用它的客户。 | ||||||
|  |  | ||||||
|  | ## 解释 | ||||||
|  |  | ||||||
|  | 现实世界例子 | ||||||
|  |  | ||||||
|  | > 屠龙是一项危险的职业。有经验将会使它变得简单。经验丰富的屠龙者对不同类型的龙有不同的战斗策略。        | ||||||
|  |  | ||||||
|  | 直白点说 | ||||||
|  |  | ||||||
|  | > 策略模式允许在运行时选择最匹配的算法。 | ||||||
|  |  | ||||||
|  | 维基百科上说 | ||||||
|  |  | ||||||
|  | > 在程序编程领域,策略模式(又叫政策模式)是一种启用在运行时选择算法的行为型软件设计模式。 | ||||||
|  |  | ||||||
|  | **编程实例** | ||||||
|  |  | ||||||
|  | 让我们先介绍屠龙的策略模式接口和它的实现。 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  | @FunctionalInterface | ||||||
|  | public interface DragonSlayingStrategy { | ||||||
|  |  | ||||||
|  |   void execute(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class MeleeStrategy implements DragonSlayingStrategy { | ||||||
|  |  | ||||||
|  |   private static final Logger LOGGER = LoggerFactory.getLogger(MeleeStrategy.class); | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void execute() { | ||||||
|  |     LOGGER.info("With your Excalibur you sever the dragon's head!"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class ProjectileStrategy implements DragonSlayingStrategy { | ||||||
|  |  | ||||||
|  |   private static final Logger LOGGER = LoggerFactory.getLogger(ProjectileStrategy.class); | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void execute() { | ||||||
|  |     LOGGER.info("You shoot the dragon with the magical crossbow and it falls dead on the ground!"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class SpellStrategy implements DragonSlayingStrategy { | ||||||
|  |  | ||||||
|  |   private static final Logger LOGGER = LoggerFactory.getLogger(SpellStrategy.class); | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void execute() { | ||||||
|  |     LOGGER.info("You cast the spell of disintegration and the dragon vaporizes in a pile of dust!"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 现在有一个强力的屠龙者要基于上面的组件来选择他的战斗策略。 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  | public class DragonSlayer { | ||||||
|  |  | ||||||
|  |   private DragonSlayingStrategy strategy; | ||||||
|  |  | ||||||
|  |   public DragonSlayer(DragonSlayingStrategy strategy) { | ||||||
|  |     this.strategy = strategy; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void changeStrategy(DragonSlayingStrategy strategy) { | ||||||
|  |     this.strategy = strategy; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void goToBattle() { | ||||||
|  |     strategy.execute(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | 最后是屠龙者的行动。 | ||||||
|  |  | ||||||
|  | ```java | ||||||
|  |     LOGGER.info("Green dragon spotted ahead!"); | ||||||
|  |     var dragonSlayer = new DragonSlayer(new MeleeStrategy()); | ||||||
|  |     dragonSlayer.goToBattle(); | ||||||
|  |     LOGGER.info("Red dragon emerges."); | ||||||
|  |     dragonSlayer.changeStrategy(new ProjectileStrategy()); | ||||||
|  |     dragonSlayer.goToBattle(); | ||||||
|  |     LOGGER.info("Black dragon lands before you."); | ||||||
|  |     dragonSlayer.changeStrategy(new SpellStrategy()); | ||||||
|  |     dragonSlayer.goToBattle(); | ||||||
|  |      | ||||||
|  |     // Green dragon spotted ahead! | ||||||
|  |     // With your Excalibur you sever the dragon's head! | ||||||
|  |     // Red dragon emerges. | ||||||
|  |     // You shoot the dragon with the magical crossbow and it falls dead on the ground! | ||||||
|  |     // Black dragon lands before you. | ||||||
|  |     // You cast the spell of disintegration and the dragon vaporizes in a pile of dust!     | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## 类图 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## 应用 | ||||||
|  | 使用策略模式当 | ||||||
|  |  | ||||||
|  | * 许多相关的类只是行为不同。策略模式提供了一种为一种类配置多种行为的能力。 | ||||||
|  | * 你需要一种算法的不同变体。比如,你可能定义反应不用时间空间权衡的算法。当这些算法的变体使用类的层次结构来实现时就可以使用策略模式。 | ||||||
|  | * 一个算法使用的数据客户不应该对其知晓。使用策略模式来避免暴露复杂的,特定于算法的数据结构。 | ||||||
|  | * 一个类定义了许多行为,这些行为在其操作中展现为多个条件语句。移动相关的条件分支到它们分别的策略类中来代替这些条件语句。 | ||||||
|  |  | ||||||
|  | ## 教学 | ||||||
|  |  | ||||||
|  | * [Strategy Pattern Tutorial](https://www.journaldev.com/1754/strategy-design-pattern-in-java-example-tutorial) | ||||||
|  |  | ||||||
|  | ## 鸣谢 | ||||||
|  |  | ||||||
|  | * [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) | ||||||
|  | * [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b) | ||||||
|  | * [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) | ||||||
|  | * [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) | ||||||
		Reference in New Issue
	
	Block a user