结构型模式描述如何将类或对象按某种布局组成更大的结构 。
image.png

适配器模式

适配器模式Adapter Pattern通过定义一个适配器作为两个不兼容接口/类之间的桥梁,使得两个或者多个不兼容的接口/类可以在一起正常地工作。实质上是接口的中间转换器
适配器主要分为三种:类适配器模式、对象适配器模式、接口适配器模式
image.png

  • Source:待适配的类或接口
  • Target: 目标的类或接口
  • Adapter: 适配器

    类适配器模式

    类适配器指的是通过类继承机制实现源类的功能。

    1. /**
    2. * 类适配器模式
    3. * 通过继承实现Source的功能
    4. */
    5. public class AdapterPattern1 {
    6. public static void main(String[] args) {
    7. Targetable targetable = new ClassAdapter();
    8. targetable.editTextFile();
    9. targetable.editWordFile();
    10. }
    11. }
    12. //Source类 实现编辑TextFile功能
    13. class Source {
    14. public void editTextFile() {
    15. System.out.println("edit TextFile");
    16. }
    17. }
    18. //目标类需要实现的接口
    19. interface Targetable {
    20. void editTextFile();
    21. void editWordFile();
    22. }
    23. //适配器:extends源类来实现Source的功能,继承Targetable来实现目标功能
    24. class ClassAdapter extends Source implements Targetable {
    25. @Override
    26. public void editTextFile() {
    27. super.editTextFile();
    28. }
    29. @Override
    30. public void editWordFile() {
    31. System.out.println("edit WordFile");
    32. }
    33. }

    对象适配器模式

    对象适配器模式是通过持有Source的实例来实现Source的功能。

    1. /**
    2. * 对象适配器模式
    3. * 通过持有Source对象来实现源类的功能
    4. */
    5. public class AdapterPattern2 {
    6. public static void main(String[] args) {
    7. Targetable target = new ClassAdapter();
    8. target.editTextFile();
    9. target.editWordFile();
    10. }
    11. static class Source {
    12. public void editTextFile() {
    13. System.out.println("edit TextFile");
    14. }
    15. }
    16. interface Targetable {
    17. void editTextFile();
    18. void editWordFile();
    19. }
    20. static class ClassAdapter implements Targetable{
    21. private Source source;
    22. public ClassAdapter() {
    23. this.source = new Source();
    24. }
    25. @Override
    26. public void editTextFile() {
    27. this.source.editTextFile();
    28. }
    29. @Override
    30. public void editWordFile() {
    31. System.out.println("edit WordFile");
    32. }
    33. }
    34. }

    接口适配器模式

    如果不希望实现一个接口中的所有方法,可以用一个AbstractAdapter继承接口,然后让TargetClass继承AbstractAdapter从而有选择性地实现接口中的方法。

    1. /**
    2. * 接口适配器
    3. * 如果不想实现接口的所有方法,可以通过 接口适配器模式来有选择性地实现接口中的方法
    4. */
    5. public class AdapterPattern3 {
    6. public static void main(String[] args) {
    7. Targetable target = new Adapter();
    8. target.editWordFile();
    9. }
    10. /**
    11. * 接口实现了两个方法
    12. */
    13. interface Targetable {
    14. void editTextFile();
    15. void editWordFile();
    16. }
    17. /**
    18. * 抽象适配器实现接口
    19. */
    20. static class AbstractAdapter implements Targetable {
    21. @Override
    22. public void editTextFile() {
    23. }
    24. @Override
    25. public void editWordFile() {
    26. }
    27. }
    28. /**
    29. * 真实Adapter : 指向实现操作WordFile的方法
    30. */
    31. static class Adapter extends AbstractAdapter {
    32. @Override
    33. public void editWordFile() {
    34. System.out.println("edit WordFile");
    35. }
    36. }
    37. }

    装饰者模式

    Decorator Pattern指的是在无需改变原有类以及类的继承关系下,动态扩展一个类的功能。核心是扩展类的功能。
    image.png

    1. public class DecoratorPattern {
    2. public static void main(String[] args) {
    3. Source source = new Source();
    4. DecoratorSource decorator = new DecoratorSource(source);
    5. decorator.func();
    6. }
    7. /**
    8. * Source与Decorator共同实现的接口
    9. */
    10. interface Sourceable {
    11. void func();
    12. }
    13. /**
    14. * 原有的类,实现基础功能
    15. */
    16. static class Source implements Sourceable {
    17. @Override
    18. public void func() {
    19. System.out.println("基础功能");
    20. }
    21. }
    22. /**
    23. * 装饰器类:扩展源类的功能
    24. */
    25. static class DecoratorSource implements Sourceable {
    26. //需要扩展功能的对象
    27. private Source source;
    28. public DecoratorSource(Source source) {
    29. this.source = source;
    30. }
    31. @Override
    32. public void func() {
    33. source.func();
    34. System.out.println("功能扩展");
    35. }
    36. }
    37. }

    代理模式

    通过**Source**类创建代理类从而扩展源类的功能。

    1. public class ProxyPattern {
    2. public static void main(String[] args) {
    3. ProxySource proxy = new ProxySource();
    4. proxy.func();
    5. }
    6. /**
    7. * 被代理类和代理类都实现的接口
    8. */
    9. interface Sourceable {
    10. void func();
    11. }
    12. /**
    13. * 被代理类,功能被增强
    14. */
    15. static class Source implements Sourceable{
    16. @Override
    17. public void func() {
    18. System.out.println("基础功能");
    19. }
    20. }
    21. /**
    22. * 代理类: 创建代理对象来扩展功能
    23. */
    24. static class ProxySource implements Sourceable {
    25. private Source source;
    26. public ProxySource() {
    27. this.source = new Source();
    28. }
    29. @Override
    30. public void func() {
    31. this.source.func();
    32. System.out.println("功能扩展");
    33. }
    34. }
    35. }

    代理模式与装饰者模式的异同

    相同点

    作用都是增强源类的功能,即实现源对象功能的基础上能够进行增强操作

    不同点

    装饰者模式实现源功能的依旧是源对象(在构造的时候需要传入对象)。而代理模式完全是新建了一个源对象的代理对象,通过代理对象来实现功能。

    外观模式

    Facade Pattern 也叫做门面模式,通过一个facade客户端提供一个访问系统的统一接口。 当一个系统的功能越来越强,子系统会越来越多,客户对系统的访问也变得越来越复杂。这时如果系统内部发生改变,客户端也要跟着改变,这违背了“开闭原则”,也违背了“迪米特法则”,所以有必要为多个子系统提供一个统一的接口,从而降低系统的耦合度,这就是外观模式的目标
    例如判断一个学生是否是一个好学生可能会由各科老师共同决定,如果学生只是轮流地去询问每一个老师,那么如果老师更换了学生也需要修改自己询问的细节。而这个时候将对所有老师的访问封装起来给学生一个统一的访问途径,就会降低学生与老师之间的耦合度。
    image.png
    外观模式需要以下几个角色:

    • 子系统角色: 实现子系统的功能
    • Facade: 提供给客户端访问系统的统一接口
    • 客户: 调用Facade来访问整个系统

以上文的老师学生为例:

  1. /**
  2. * 外观模式
  3. */
  4. public class FacadePattern {
  5. public static void main(String[] args) {
  6. Student student = new Student(1,"张三",70,80,90);
  7. Facade facade = new Facade();
  8. System.out.println(facade.isGood(student));
  9. }
  10. }
  11. /**
  12. * 外观类:封装了子系统,给使用者一个统一的接口
  13. */
  14. class Facade {
  15. private MathTeacher mathTeacher = new MathTeacher();
  16. private ChineseTeacher chineseTeacher = new ChineseTeacher();
  17. private EnglishTeacher englishTeacher = new EnglishTeacher();
  18. //封装所有子系统isGood的功能,统一返回给用户
  19. public boolean isGood(Student student) {
  20. return mathTeacher.isGood(student) && chineseTeacher.isGood(student) && englishTeacher.isGood(student);
  21. }
  22. }
  23. //子系统角色1:数学老师
  24. class MathTeacher {
  25. public boolean isGood(Student student) {
  26. return student.math > 60? true:false;
  27. }
  28. }
  29. //子系统角色2:英语老师
  30. class EnglishTeacher {
  31. public boolean isGood(Student student) {
  32. return student.english > 60? true:false;
  33. }
  34. }
  35. //子系统角色3:语文老师
  36. class ChineseTeacher {
  37. public boolean isGood(Student student) {
  38. return student.chinese>0? true:false;
  39. }
  40. }
  41. //外观使用者:学生
  42. class Student {
  43. protected int id;
  44. protected String name;
  45. protected int math;
  46. protected int chinese;
  47. protected int english;
  48. public Student(int id, String name, int math, int chinese, int english) {
  49. this.id = id;
  50. this.name = name;
  51. this.math = math;
  52. this.chinese = chinese;
  53. this.english = english;
  54. }
  55. }

外观模式和建造者模式的异同

相同点

两者都是将一个复杂的流程封装在了一个类中,对外提供简单的同一访问接口

不同点
  • 建造者模式针对的是构造复杂对象,属于创建型设计模式。而外观模式针对的是如何将子系统组成一个对外统一的结构,属于结构型设计模式
  • 建造者模式聚焦于返回对象,外观模式聚焦于完成某个动作或功能

    桥接模式

    Bridge Pattern将抽象部分与它的实现部分分离开来,使得他们都可以独立地变化。通过将继承关系转化为关联关系,从而降低了类与类之间的耦合度。
    桥接模式涉及的角色有:
  • 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
  • 修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
  • 实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。
  • 具体实现化(ConcreteImplementor)角色:这个角色给出实现化角色接口的具体实现。

    桥接模式最为典型的实现就是Java中的JDBC连接,JDBC中同时存在驱动规范连接规范两个需要独立变化的模块。接下来利用桥接模式简单实现JDBC
    image.png ```java /*

  • 桥接模式
  • */ public class BridgePattern { public static void main(String[] args) {

      //使用桥接模式
      DriverManager driverManager = new MysqlDriver(new MysqlConnection());
      driverManager.DriverInit();
      driverManager.connection.ConnectionInit();
    

    }

    /**

    • 以Driver驱动规范作为抽象 */ static abstract class DriverManager { protected Connection connection; public DriverManager(Connection connection) {
       this.connection = connection;
      
      } //Driver的实现 public abstract void DriverInit(); } /**
    • Mysql抽象实现 */ static class MysqlDriver extends DriverManager {

      public MysqlDriver(Connection connection) {

       super(connection);
      

      }

      @Override public void DriverInit() {

       System.out.println("实现Mysql Driver");
      

      } } /**

    • Oracle抽象实现 */ static class OracleDriver extends DriverManager {

      public OracleDriver(Connection connection) {

       super(connection);
      

      }

      @Override public void DriverInit() {

       System.out.println("实现Oracle Driver");
      

      } } /**

    • 以Connectin连接规范作为实现 / interface Connection { //Connection的实现 void ConnectionInit(); } /**
    • Mysql实现 */ static class MysqlConnection implements Connection { @Override public void ConnectionInit() {
       System.out.println("实现Mysql Connection");
      
      } } /**
    • Oracle实现 */ static class Oracle implements Connection { @Override public void ConnectionInit() {
       System.out.println("实现Oracle Connection");
      
      } } } ``` 可见桥接模式的特点就是让两个不同的维度能够独立地变化