diff --git a/zh/bridge/README.md b/zh/bridge/README.md new file mode 100644 index 000000000..cd9f40ac4 --- /dev/null +++ b/zh/bridge/README.md @@ -0,0 +1,205 @@ +--- +layout: pattern +title: Bridge +folder: bridge +permalink: /patterns/bridge/ +categories: Structural +tags: + - Gang of Four +--- + +## 又被称为 + +手柄/身体模式 + +## 目的 + +将抽象与其实现分离,以便二者可以独立变化。 + +## 解释 + +真实世界例子 + +> 考虑一下你拥有一种具有不同附魔的武器,并且应该允许将具有不同附魔的不同武器混合使用。 你会怎么做? 为每个附魔创建每种武器的多个副本,还是只是创建单独的附魔并根据需要为武器设置它? 桥接模式使您可以进行第二次操作。 + +通俗的说 + +> 桥接模式是一个更推荐组合而不是继承的模式。将实现细节从一个层次结构推送到具有单独层次结构的另一个对象。 + +维基百科说 + +> 桥接模式是软件工程中使用的一种设计模式,旨在“将抽象与其实现分离,从而使两者可以独立变化” + +**程序示例** + +翻译一下上面的武器示例。下面我们有武器的类层级: + +```java +public interface Weapon { + void wield(); + void swing(); + void unwield(); + Enchantment getEnchantment(); +} + +public class Sword implements Weapon { + + private final Enchantment enchantment; + + public Sword(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The sword is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The sword is swinged."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The sword is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} + +public class Hammer implements Weapon { + + private final Enchantment enchantment; + + public Hammer(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The hammer is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The hammer is swinged."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The hammer is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} +``` + +这里是单独的附魔类结构: + +```java +public interface Enchantment { + void onActivate(); + void apply(); + void onDeactivate(); +} + +public class FlyingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item begins to glow faintly."); + } + + @Override + public void apply() { + LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand."); + } + + @Override + public void onDeactivate() { + LOGGER.info("The item's glow fades."); + } +} + +public class SoulEatingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item spreads bloodlust."); + } + + @Override + public void apply() { + LOGGER.info("The item eats the soul of enemies."); + } + + @Override + public void onDeactivate() { + LOGGER.info("Bloodlust slowly disappears."); + } +} +``` + +这里是两种层次结构的实践: + +```java +var enchantedSword = new Sword(new SoulEatingEnchantment()); +enchantedSword.wield(); +enchantedSword.swing(); +enchantedSword.unwield(); +// The sword is wielded. +// The item spreads bloodlust. +// The sword is swinged. +// The item eats the soul of enemies. +// The sword is unwielded. +// Bloodlust slowly disappears. + +var hammer = new Hammer(new FlyingEnchantment()); +hammer.wield(); +hammer.swing(); +hammer.unwield(); +// The hammer is wielded. +// The item begins to glow faintly. +// The hammer is swinged. +// The item flies and strikes the enemies finally returning to owner's hand. +// The hammer is unwielded. +// The item's glow fades. +``` + + + +## 类图 + +![alt text](../../bridge/etc/bridge.urm.png "Bridge class diagram") + +## 适用性 + +使用桥接模式当 + +* 你想永久性的避免抽象和他的实现之间的绑定。有可能是这种情况,当实现需要被选择或者在运行时切换。 +* 抽象和他们的实现应该能通过写子类来扩展。这种情况下,桥接模式让你可以组合不同的抽象和实现并独立的扩展他们。 +* 对抽象的实现的改动应当不会对客户产生影响;也就是说,他们的代码不必重新编译。 +* 你有种类繁多的类。这样的类层次结构表明需要将一个对象分为两部分。Rumbaugh 使用术语“嵌套归纳”来指代这种类层次结构。 +* 你想在多个对象间分享一种实现(可能使用引用计数),这个事实应该对客户隐藏。一个简单的示例是Coplien的String类,其中多个对象可以共享同一字符串表示形式 + +## 教程 + +* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java) + +## 鸣谢 + +* [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) +* [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) diff --git a/zh/decorator/README.md b/zh/decorator/README.md index ef23eda0b..6163017af 100644 --- a/zh/decorator/README.md +++ b/zh/decorator/README.md @@ -33,8 +33,6 @@ tags: 以巨魔的为例。首先我有有一个简单的巨魔,实现了巨魔接口。 -程序mple. First of all we have a simple troll implementing the troll interface - ```java public interface Troll { void attack(); diff --git a/zh/dependency-injection/README.md b/zh/dependency-injection/README.md new file mode 100644 index 000000000..061a55425 --- /dev/null +++ b/zh/dependency-injection/README.md @@ -0,0 +1,101 @@ +--- +layout: pattern +title: Dependency Injection +folder: dependency-injection +permalink: /patterns/dependency-injection/ +categories: Creational +tags: + - Decoupling +--- + +## 目的 + +依赖注入是一种软件设计模式,其中一个或多个依赖项(或服务)被注入或通过引用传递到一个依赖对象(或客户端)中,并成为客户端状态的一部分。该模式将客户的依赖关系的创建与其自身的行为分开,这使程序设计可以松散耦合,并遵循控制反转和单一职责原则。 + +## 解释 + +真实世界例子 + +> 老巫师喜欢不时地装满烟斗抽烟。 但是,他不想只依赖一个烟草品牌,而是希望能够互换使用它们。 + +通俗的说 + +> 依赖注入将客户端依赖的创建与其自身行为分开。 + +维基百科说 + +> 在软件工程中,依赖注入是一种对象接收其依赖的其他对象的技术。 这些其他对象称为依赖项。 + +**程序示例** + +先介绍一下烟草接口和具体的品牌。 + +```java +public abstract class Tobacco { + + private static final Logger LOGGER = LoggerFactory.getLogger(Tobacco.class); + + public void smoke(Wizard wizard) { + LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(), + this.getClass().getSimpleName()); + } +} + +public class SecondBreakfastTobacco extends Tobacco { +} + +public class RivendellTobacco extends Tobacco { +} + +public class OldTobyTobacco extends Tobacco { +} +``` + +下面是老巫师的类的层次结构。 + +```java +public interface Wizard { + + void smoke(); +} + +public class AdvancedWizard implements Wizard { + + private final Tobacco tobacco; + + public AdvancedWizard(Tobacco tobacco) { + this.tobacco = tobacco; + } + + @Override + public void smoke() { + tobacco.smoke(this); + } +} +``` + +最后我们可以看到给老巫师任意品牌的烟草是多么的简单。 + +```java + var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco()); + advancedWizard.smoke(); +``` + +## 类图 + +![alt text](../../dependency-injection/etc/dependency-injection.png "Dependency Injection") + +## 适用性 + +使用依赖注入当: + +- 当你需要从对象中移除掉具体的实现内容时 + +* 使用模拟对象或存根隔离地启用类的单元测试 + +## 鸣谢 + +* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd) +* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871) +* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1) +* [Google Guice Tutorial: Open source Java based dependency injection framework](https://www.amazon.com/gp/product/B083P7DZ8M/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B083P7DZ8M&linkId=04f0f902c877921e45215b624a124bfe)