| 基础知识 | 名称 | 意图 | 原型图 | 适用性 | 原型图 | 适用性 | ||
| 创建型模式(Creational Patterns) | 原型模式(Prototype) | 用原型实例指定创建对象的种类,并复制这些原型创建新的对象。 | ![]() | Prototype 模式适用于: 当一个系统应该独立于它的产品创建、构成和表示时。 当要实例化的类是在运行时刻指定时,例如,通过动态装载。为了避免创建一个与产品类层次平行的工厂类层次时。 。当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的们,可能比每次用合适的状态手工实例化该类更方便一些。 | interface Shape { void draw(); } class Circle implements Shape { private String color; private int radius; public Circle(String color) { this.color = color; this.radius = 1; // 默认半径 } // Getter 和 Setter public void setColor(String color) { this.color = color; } public String getColor() { return color; } public void setRadius(int radius) { this.radius = radius; } public int getRadius() { return radius; } @Override public void draw() { System.out.println("Inside Circle::draw() method."); System.out.println("Circle: Draw() [Color : " + color + ", radius :" + radius); } // 实现克隆方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } |
| Prototype 模式适用于: 当一个系统应该独立于它的产品创建、构成和表示时。 当要实例化的类是在运行时刻指定时,例如,通过动态装载。为了避免创建一个与产品类层次平行的工厂类层次时。 。当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的们,可能比每次用合适的状态手工实例化该类更方便一些。 | interface Shape { void draw(); } class Circle implements Shape { private String color; private int radius; public Circle(String color) { this.color = color; this.radius = 1; // 默认半径 } // Getter 和 Setter public void setColor(String color) { this.color = color; } public String getColor() { return color; } public void setRadius(int radius) { this.radius = radius; } public int getRadius() { return radius; } @Override public void draw() { System.out.println("Inside Circle::draw() method."); System.out.println("Circle: Draw() [Color : " + color + ", radius :" + radius); } // 实现克隆方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } |
| 单例模式(Singleton) | 一个类仅有一个示例,提供一个访问全局的访问的点 | ![]() | 只能有一个实例。 | 懒汉式(线程不安全)public class Singleton { // 私有静态变量,存储唯一实例 private static Singleton instance; // 私有构造函数,防止外部直接实例化 private Singleton() {} // 提供一个全局访问点 public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } // 其他方法... } |
| 只能有一个实例。 | 懒汉式(线程不安全)public class Singleton { // 私有静态变量,存储唯一实例 private static Singleton instance; // 私有构造函数,防止外部直接实例化 private Singleton() {} // 提供一个全局访问点 public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } // 其他方法... } | |
| 工厂方法模式(Factory Method) | 定义一个用于创建对象的接口,让子类决定实现实例化哪一个类。 | ![]() | Factory Method 模式适用于: 当一个类不知道它所必须创建的对象的类的时候。 当一个类希望由它的子类来指定它所创建的对象的时候。 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个类是代理者这一信息局部化的时候。 | 步骤 1 创建一个接口: Shape.java public interface Shape { void draw(); } 步骤 2 创建实现接口的实体类。 Rectangle.java public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } } Square.java public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } } Circle.java public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } } 步骤 3 创建一个工厂,生成基于给定信息的实体类的对象。 ShapeFactory.java public class ShapeFactory { //使用 getShape 方法获取形状类型的对象 public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } } 步骤 4 使用该工厂,通过传递类型信息来获取实体类的对象。 FactoryPatternDemo.java public class FactoryPatternDemo { public static void main(String[] args) { ShapeFactory shapeFactory = new ShapeFactory(); //获取 Circle 的对象,并调用它的 draw 方法 Shape shape1 = shapeFactory.getShape("CIRCLE"); //调用 Circle 的 draw 方法 shape1.draw(); //获取 Rectangle 的对象,并调用它的 draw 方法 Shape shape2 = shapeFactory.getShape("RECTANGLE"); //调用 Rectangle 的 draw 方法 shape2.draw(); //获取 Square 的对象,并调用它的 draw 方法 Shape shape3 = shapeFactory.getShape("SQUARE"); //调用 Square 的 draw 方法 shape3.draw(); } } |
| Factory Method 模式适用于: 当一个类不知道它所必须创建的对象的类的时候。 当一个类希望由它的子类来指定它所创建的对象的时候。 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个类是代理者这一信息局部化的时候。 | 步骤 1 创建一个接口: Shape.java public interface Shape { void draw(); } 步骤 2 创建实现接口的实体类。 Rectangle.java public class Rectangle implements Shape { @Override public void draw() { System.out.println("Inside Rectangle::draw() method."); } } Square.java public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } } Circle.java public class Circle implements Shape { @Override public void draw() { System.out.println("Inside Circle::draw() method."); } } 步骤 3 创建一个工厂,生成基于给定信息的实体类的对象。 ShapeFactory.java public class ShapeFactory { //使用 getShape 方法获取形状类型的对象 public Shape getShape(String shapeType){ if(shapeType == null){ return null; } if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } else if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } else if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } } 步骤 4 使用该工厂,通过传递类型信息来获取实体类的对象。 FactoryPatternDemo.java public class FactoryPatternDemo { public static void main(String[] args) { ShapeFactory shapeFactory = new ShapeFactory(); //获取 Circle 的对象,并调用它的 draw 方法 Shape shape1 = shapeFactory.getShape("CIRCLE"); //调用 Circle 的 draw 方法 shape1.draw(); //获取 Rectangle 的对象,并调用它的 draw 方法 Shape shape2 = shapeFactory.getShape("RECTANGLE"); //调用 Rectangle 的 draw 方法 shape2.draw(); //获取 Square 的对象,并调用它的 draw 方法 Shape shape3 = shapeFactory.getShape("SQUARE"); //调用 Square 的 draw 方法 shape3.draw(); } } | |
| 抽象工厂模式(Abstract Factory) | 提供一个创建一系列相关或相互依赖对象的接口,无需指定具体的类。 | ![]() | 建议在如下情况中,选用抽象工厂模式: 如果希望一个系统独立于它的产品的创建,组合和表示的时候,换句话说,希望一个系统只是知道产品的接口,而不关心实现的时候; 如果一个系统要由多个产品系列中的一个来配置的时候,换句话说,就是可以动态的切换产品簇的时候; 如果要强调一系列相关产品的接口,以便联合使用它们的时候。 四,抽象工厂模式的本质 抽象工厂模式的本质是:选择产品簇的实现.抽象工厂着重的就是为一个产品簇选择实现,定义在抽象工厂里面的方法通常是有联系的,它们都是产品的某一部分或者是相互依赖的。 | public interface AbstractFactory { public AbstractProductA CreateProductA(); public AbstractProductB CreateProductB(); }; public abstract class AbstractProductA { public void operationA(); }; public abstract class AbstractProductB { public void operationB(); }; class ProductA1 : extends AbstractProductA { public void operationA(); }; class ProductA2 : extends AbstractProductA { public void operationA(); }; class ProductB1 : extends AbstractProductB { public void operationB(); }; class ProductB2 : extends AbstractProductB { public void operationB(); }; class ConcreteFactory1 : implements AbstractFactory { public AbstractProductA CreateProductA() { return new ProductA1(); } public AbstractProductB CreateProductB() { return new ProductB1(); } }; class ConcreteFactory2 : implements AbstractFactory { public AbstractProductA CreateProductA() { return new ProductA2(); } public AbstractProductB CreateProductB() { return new ProductB2(); } }; public class Client { public static void main(String[] args) { AbstractFactory factory1 = new ConcreteFactory1(); AbstractProductA productA1 = factory1.createProductA(); AbstractProductB productB1 = factory1.createProductB(); productA1.operationA(); productB1.operationB(); AbstractFactory factory2 = new ConcreteFactory2(); AbstractProductA productA2 = factory2.createProductA(); AbstractProductB productB2 = factory2.createProductB(); productA2.operationA(); productB2.operationB(); } } |
| 建议在如下情况中,选用抽象工厂模式: 如果希望一个系统独立于它的产品的创建,组合和表示的时候,换句话说,希望一个系统只是知道产品的接口,而不关心实现的时候; 如果一个系统要由多个产品系列中的一个来配置的时候,换句话说,就是可以动态的切换产品簇的时候; 如果要强调一系列相关产品的接口,以便联合使用它们的时候。 四,抽象工厂模式的本质 抽象工厂模式的本质是:选择产品簇的实现.抽象工厂着重的就是为一个产品簇选择实现,定义在抽象工厂里面的方法通常是有联系的,它们都是产品的某一部分或者是相互依赖的。 | public interface AbstractFactory { public AbstractProductA CreateProductA(); public AbstractProductB CreateProductB(); }; public abstract class AbstractProductA { public void operationA(); }; public abstract class AbstractProductB { public void operationB(); }; class ProductA1 : extends AbstractProductA { public void operationA(); }; class ProductA2 : extends AbstractProductA { public void operationA(); }; class ProductB1 : extends AbstractProductB { public void operationB(); }; class ProductB2 : extends AbstractProductB { public void operationB(); }; class ConcreteFactory1 : implements AbstractFactory { public AbstractProductA CreateProductA() { return new ProductA1(); } public AbstractProductB CreateProductB() { return new ProductB1(); } }; class ConcreteFactory2 : implements AbstractFactory { public AbstractProductA CreateProductA() { return new ProductA2(); } public AbstractProductB CreateProductB() { return new ProductB2(); } }; public class Client { public static void main(String[] args) { AbstractFactory factory1 = new ConcreteFactory1(); AbstractProductA productA1 = factory1.createProductA(); AbstractProductB productB1 = factory1.createProductB(); productA1.operationA(); productB1.operationB(); AbstractFactory factory2 = new ConcreteFactory2(); AbstractProductA productA2 = factory2.createProductA(); AbstractProductB productB2 = factory2.createProductB(); productA2.operationA(); productB2.operationB(); } } | |
| 建造者模式(Builder) | 将一个复杂对象的构建和他的表示分离。 | ![]() | 当创建复杂对象的算法应该独立于对象的组成部分以及他们的装配方式。 | package com.designpattern.builder; /** * 抽象建造类,提供创建产品的共同接口,不同的产品可以有自己的具体实现 * @author * */ public abstract class AbstractBuilder { /** * 创建引擎 */ public abstract void buildEngine(); /** * 创建车玻璃 */ public abstract void buildGlass(); /** * 创建方向盘 */ public abstract void buildSteeringWheel(); /** * 返回创建好的产品,为了兼容所有的产品,返回的类型定为共同的父类 * @return */ public abstract Car getCar(); } package com.designpattern.builder; /** * Audi的具体创建者 * @author xingjiarong * */ public class AudiBuilder extends AbstractBuilder{ /** * 创建一个各部分都为空的对象 */ Audi audi = new Audi(); /** * 创建各个部分 */ public void buildEngine() { audi.engine = "AudiEngine"; } public void buildGlass() { audi.glass = 3.5; } public void buildSteeringWheel() { audi.steeringWheel = "AudiSteeringWheel"; } /** * 返回创建好的对象 */ public Car getCar() { return audi; } } package com.designpattern.builder; /** * 导演类,根据按照产品的建造和组装顺序组装产品 * @author xingjiarong * */ public class Director { private AbstractBuilder build; public Director(AbstractBuilder build){ this.build = build; } /*** * 组成产品的方法,组成的过程可能是有顺序的 * @return */ public Car construct(){ build.buildSteeringWheel(); build.buildGlass(); build.buildEngine(); return build.getCar(); } } package com.designpattern.builder; public abstract class Car { /** * 汽车引擎,实际应用中应该是一个对象,这里用字符串来表示 */ public String engine; /** * 汽车玻璃,不同的汽车大小不一样,需要根据汽车的型号计算 */ public double glass; /** * 汽车方向盘 */ public String steeringWheel; public abstract void drive(); } package com.designpattern.builder; public class Main { public static void main(String[] args) throws Exception { /** * 创建导演类和Audi的建造者 */ AudiBuilder build = new AudiBuilder(); Director director = new Director(build); /** * 利用导演类获得汽车而不是自己获得汽车 */ Car car = director.construct(); //开车 car.drive(); } } |
| 当创建复杂对象的算法应该独立于对象的组成部分以及他们的装配方式。 | package com.designpattern.builder; /** * 抽象建造类,提供创建产品的共同接口,不同的产品可以有自己的具体实现 * @author * */ public abstract class AbstractBuilder { /** * 创建引擎 */ public abstract void buildEngine(); /** * 创建车玻璃 */ public abstract void buildGlass(); /** * 创建方向盘 */ public abstract void buildSteeringWheel(); /** * 返回创建好的产品,为了兼容所有的产品,返回的类型定为共同的父类 * @return */ public abstract Car getCar(); } package com.designpattern.builder; /** * Audi的具体创建者 * @author xingjiarong * */ public class AudiBuilder extends AbstractBuilder{ /** * 创建一个各部分都为空的对象 */ Audi audi = new Audi(); /** * 创建各个部分 */ public void buildEngine() { audi.engine = "AudiEngine"; } public void buildGlass() { audi.glass = 3.5; } public void buildSteeringWheel() { audi.steeringWheel = "AudiSteeringWheel"; } /** * 返回创建好的对象 */ public Car getCar() { return audi; } } package com.designpattern.builder; /** * 导演类,根据按照产品的建造和组装顺序组装产品 * @author xingjiarong * */ public class Director { private AbstractBuilder build; public Director(AbstractBuilder build){ this.build = build; } /*** * 组成产品的方法,组成的过程可能是有顺序的 * @return */ public Car construct(){ build.buildSteeringWheel(); build.buildGlass(); build.buildEngine(); return build.getCar(); } } package com.designpattern.builder; public abstract class Car { /** * 汽车引擎,实际应用中应该是一个对象,这里用字符串来表示 */ public String engine; /** * 汽车玻璃,不同的汽车大小不一样,需要根据汽车的型号计算 */ public double glass; /** * 汽车方向盘 */ public String steeringWheel; public abstract void drive(); } package com.designpattern.builder; public class Main { public static void main(String[] args) throws Exception { /** * 创建导演类和Audi的建造者 */ AudiBuilder build = new AudiBuilder(); Director director = new Director(build); /** * 利用导演类获得汽车而不是自己获得汽车 */ Car car = director.construct(); //开车 car.drive(); } } | |
| 结构型模式(Structural Patterns) | 适配器模式(Adapter) | 将一个类的接口转换成客户希望的另一个接口形式。适配器让原本接口不兼容的类可以一起工作。 | ![]() | 当需要将一个类的接口转换成客户端所期望的另一个接口时。 当需要使用一些已经存在的类,但它们的接口与当前系统不兼容时。 | 1. 定义一个插座接口 首先,我们定义一个插座的接口,代表可以接收插头的插座。 java public interface Socket { void powerOn(Plug plug); } // 美国插座 class AmericanSocket implements Socket { @Override public void powerOn(Plug plug) { if (plug instanceof AmericanPlug) { System.out.println("American Socket powering on the device."); } else { System.out.println("Incompatible plug, cannot power on."); } } } 2. 定义插头接口 接着,我们定义插头的接口,表示电器的插头。 java public interface Plug { // 这里可以定义一些方法,比如验证插头类型等 } // 欧洲插头 class EuropeanPlug implements Plug { // 欧洲插头特有的方法或属性 } // 美国插头 class AmericanPlug implements Plug { // 美国插头特有的方法或属性 } 3. 创建适配器 然后,我们创建一个适配器类,它实现了插头的接口,但是内部持有欧洲插头的实例,并且提供一个美国插头接口的方法,使得美国插座可以识别并使用它。 java class PlugAdapter implements AmericanPlug { private EuropeanPlug europeanPlug; public PlugAdapter(EuropeanPlug europeanPlug) { this.europeanPlug = europeanPlug; } // 这里可以添加转换逻辑,但在这个例子中,我们只是简单地将欧洲插头“适配”为美国插头 // 实际上,转换可能涉及到电压、电流等复杂因素的转换 // 注意:这个适配器只是模拟了插头形状的适配,并没有真正转换电气特性 } // 注意:由于我们的`AmericanSocket`和`AmericanPlug`接口设计相对简单,没有实质性的转换逻辑需要实现, // 所以这里的`PlugAdapter`实现看起来可能有些“空”。在实际应用中,适配器可能会包含复杂的转换逻辑。 4. 使用适配器 最后,我们可以看看如何使用适配器来连接欧洲电器和美国插座。 java public class AdapterPatternDemo { public static void main(String[] args) { AmericanSocket americanSocket = new AmericanSocket(); EuropeanPlug europeanPlug = new EuropeanPlug(); // 适配器创建 // 注意:由于我们的适配器类`PlugAdapter`实现较为简单,没有实际的转换逻辑, // 所以这里只是演示如何创建适配器对象,并未真正展示其转换功能 // PlugAdapter plugAdapter = new PlugAdapter(europeanPlug); // 理论上,这里应该使用plugAdapter来连接插座和插头 // 但由于我们的示例中适配器类较为简单,我们直接略过这一步 // 实际上,由于我们的示例设计,这里的适配器类并不是必须的, // 因为没有实际的电气特性转换。但在真实场景中,适配器是必需的。 // 直接输出说明,因为示例的限制 System.out.println("Using an adapter (if needed) to connect European plug to American socket."); } } 注意:由于示例的简化,上述代码并没有真正展示适配器模式在电气特性转换方面的作用。在实际应用中,适配器模式通常用于处理更为复杂的接口不匹配问题,包括但不限于电气特性、数据格式、协议等方面的转换。 |
| 当需要将一个类的接口转换成客户端所期望的另一个接口时。 当需要使用一些已经存在的类,但它们的接口与当前系统不兼容时。 | 1. 定义一个插座接口 首先,我们定义一个插座的接口,代表可以接收插头的插座。 java public interface Socket { void powerOn(Plug plug); } // 美国插座 class AmericanSocket implements Socket { @Override public void powerOn(Plug plug) { if (plug instanceof AmericanPlug) { System.out.println("American Socket powering on the device."); } else { System.out.println("Incompatible plug, cannot power on."); } } } 2. 定义插头接口 接着,我们定义插头的接口,表示电器的插头。 java public interface Plug { // 这里可以定义一些方法,比如验证插头类型等 } // 欧洲插头 class EuropeanPlug implements Plug { // 欧洲插头特有的方法或属性 } // 美国插头 class AmericanPlug implements Plug { // 美国插头特有的方法或属性 } 3. 创建适配器 然后,我们创建一个适配器类,它实现了插头的接口,但是内部持有欧洲插头的实例,并且提供一个美国插头接口的方法,使得美国插座可以识别并使用它。 java class PlugAdapter implements AmericanPlug { private EuropeanPlug europeanPlug; public PlugAdapter(EuropeanPlug europeanPlug) { this.europeanPlug = europeanPlug; } // 这里可以添加转换逻辑,但在这个例子中,我们只是简单地将欧洲插头“适配”为美国插头 // 实际上,转换可能涉及到电压、电流等复杂因素的转换 // 注意:这个适配器只是模拟了插头形状的适配,并没有真正转换电气特性 } // 注意:由于我们的`AmericanSocket`和`AmericanPlug`接口设计相对简单,没有实质性的转换逻辑需要实现, // 所以这里的`PlugAdapter`实现看起来可能有些“空”。在实际应用中,适配器可能会包含复杂的转换逻辑。 4. 使用适配器 最后,我们可以看看如何使用适配器来连接欧洲电器和美国插座。 java public class AdapterPatternDemo { public static void main(String[] args) { AmericanSocket americanSocket = new AmericanSocket(); EuropeanPlug europeanPlug = new EuropeanPlug(); // 适配器创建 // 注意:由于我们的适配器类`PlugAdapter`实现较为简单,没有实际的转换逻辑, // 所以这里只是演示如何创建适配器对象,并未真正展示其转换功能 // PlugAdapter plugAdapter = new PlugAdapter(europeanPlug); // 理论上,这里应该使用plugAdapter来连接插座和插头 // 但由于我们的示例中适配器类较为简单,我们直接略过这一步 // 实际上,由于我们的示例设计,这里的适配器类并不是必须的, // 因为没有实际的电气特性转换。但在真实场景中,适配器是必需的。 // 直接输出说明,因为示例的限制 System.out.println("Using an adapter (if needed) to connect European plug to American socket."); } } 注意:由于示例的简化,上述代码并没有真正展示适配器模式在电气特性转换方面的作用。在实际应用中,适配器模式通常用于处理更为复杂的接口不匹配问题,包括但不限于电气特性、数据格式、协议等方面的转换。 |
| 桥接模式(Bridge) | 将抽象部分与它的实现部分分离,使它们都可以独立地变化。 | 适用性 模式适用于:不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如,这种情况可能是园为在程序运行时刻实现部分应可以被选择或者切换。类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这是Bidge 模式使得开发者可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译。(C++)想对客户完全隐藏抽象的实现部分。 有许多类要生成的类层次结构。 想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。 | // 形状接口(Abstraction),包含一个对颜色的引用 abstract class Shape { protected Color color; // 构造函数,用于设置颜色 public Shape(Color color) { this.color = color; } // 抽象方法,由子类实现具体的绘图逻辑 abstract void draw(); // 调用颜色的applyColor方法 public void applyColor() { color.applyColor(); } } // 圆形类(Refined Abstraction),扩展了Shape类 class Circle extends Shape { public Circle(Color color) { super(color); } @Override void draw() { System.out.println("Drawing Circle..."); applyColor(); // 调用颜色的applyColor方法 } } // 矩形类(Refined Abstraction),扩展了Shape类 class Rectangle extends Shape { public Rectangle(Color color) { super(color); } @Override void draw() { System.out.println("Drawing Rectangle..."); applyColor(); // 调用颜色的applyColor方法 } } |
| 适用性 模式适用于:不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如,这种情况可能是园为在程序运行时刻实现部分应可以被选择或者切换。类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这是Bidge 模式使得开发者可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译。(C++)想对客户完全隐藏抽象的实现部分。 有许多类要生成的类层次结构。 想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。 | // 形状接口(Abstraction),包含一个对颜色的引用 abstract class Shape { protected Color color; // 构造函数,用于设置颜色 public Shape(Color color) { this.color = color; } // 抽象方法,由子类实现具体的绘图逻辑 abstract void draw(); // 调用颜色的applyColor方法 public void applyColor() { color.applyColor(); } } // 圆形类(Refined Abstraction),扩展了Shape类 class Circle extends Shape { public Circle(Color color) { super(color); } @Override void draw() { System.out.println("Drawing Circle..."); applyColor(); // 调用颜色的applyColor方法 } } // 矩形类(Refined Abstraction),扩展了Shape类 class Rectangle extends Shape { public Rectangle(Color color) { super(color); } @Override void draw() { System.out.println("Drawing Rectangle..."); applyColor(); // 调用颜色的applyColor方法 } } | ||
| 组合模式(Composite) | 将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户对单个对象和组合对象的使用具有一致性。 | ![]() | 对象的整体-层次结构 | 定义组件接口 首先,我们定义一个组件接口(Component),它声明了所有对象(无论是文件还是文件夹)共有的方法。 java interface FileSystemComponent { void display(); } 2. 实现叶节点(文件) 然后,我们实现一个表示文件的类(File),它实现了FileSystemComponent接口。 java class File implements FileSystemComponent { private String name; public File(String name) { this.name = name; } @Override public void display() { System.out.println(name); } } 3. 实现容器节点(文件夹) 接着,我们实现一个表示文件夹的类(Folder),它也实现了FileSystemComponent接口,并包含一个FileSystemComponent类型的列表来存储其子元素(文件和文件夹)。 java import java.util.ArrayList; import java.util.List; class Folder implements FileSystemComponent { private String name; private List<FileSystemComponent> children = new ArrayList<>(); public Folder(String name) { this.name = name; } // 添加子元素 public void add(FileSystemComponent component) { children.add(component); } // 移除子元素 public void remove(FileSystemComponent component) { children.remove(component); } @Override public void display() { System.out.println(name + "/"); for (FileSystemComponent component : children) { component.display(); } } } 4. 客户端代码 最后,在客户端代码中,我们可以创建文件和文件夹对象,并将它们组合起来形成树形结构,然后调用display方法来展示整个文件系统的结构。 java public class CompositePatternDemo { public static void main(String[] args) { // 创建文件和文件夹 File file1 = new File("file1.txt"); File file2 = new File("file2.txt"); Folder folder1 = new Folder("folder1"); Folder folder2 = new Folder("folder2"); // 组合文件和文件夹 folder1.add(file1); folder2.add(file2); folder1.add(folder2); // 显示文件系统结构 folder1.display(); } } |
| 对象的整体-层次结构 | 定义组件接口 首先,我们定义一个组件接口(Component),它声明了所有对象(无论是文件还是文件夹)共有的方法。 java interface FileSystemComponent { void display(); } 2. 实现叶节点(文件) 然后,我们实现一个表示文件的类(File),它实现了FileSystemComponent接口。 java class File implements FileSystemComponent { private String name; public File(String name) { this.name = name; } @Override public void display() { System.out.println(name); } } 3. 实现容器节点(文件夹) 接着,我们实现一个表示文件夹的类(Folder),它也实现了FileSystemComponent接口,并包含一个FileSystemComponent类型的列表来存储其子元素(文件和文件夹)。 java import java.util.ArrayList; import java.util.List; class Folder implements FileSystemComponent { private String name; private List<FileSystemComponent> children = new ArrayList<>(); public Folder(String name) { this.name = name; } // 添加子元素 public void add(FileSystemComponent component) { children.add(component); } // 移除子元素 public void remove(FileSystemComponent component) { children.remove(component); } @Override public void display() { System.out.println(name + "/"); for (FileSystemComponent component : children) { component.display(); } } } 4. 客户端代码 最后,在客户端代码中,我们可以创建文件和文件夹对象,并将它们组合起来形成树形结构,然后调用display方法来展示整个文件系统的结构。 java public class CompositePatternDemo { public static void main(String[] args) { // 创建文件和文件夹 File file1 = new File("file1.txt"); File file2 = new File("file2.txt"); Folder folder1 = new Folder("folder1"); Folder folder2 = new Folder("folder2"); // 组合文件和文件夹 folder1.add(file1); folder2.add(file2); folder1.add(folder2); // 显示文件系统结构 folder1.display(); } } | |
| 装饰器模式(Decorator) | 动态地给一个对象添加一些额外的职责。就扩展功能而言,装饰器模式相比生成子类更为灵活。 | ![]() | 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责处理那些可以撤销的职责。 当不能采用生成子类的方式进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是,由于类定义被隐藏,或类定义不能用于生成子类。 | 定义咖啡基类 首先,我们定义一个咖啡基类,它有一个方法用于获取咖啡的描述。 java // 咖啡基类 abstract class Coffee { String description = "Unknown Coffee"; // 获取咖啡描述 public String getDescription() { return description; } // 定义一个方法来准备咖啡(抽象方法,具体咖啡类型会实现它) public abstract double cost(); } 2. 定义具体的咖啡类 接着,我们定义几个具体的咖啡类,比如美式咖啡和拿铁咖啡。 java // 美式咖啡 class Americano extends Coffee { public Americano() { description = "Americano"; } @Override public double cost() { return 1.5; } } // 拿铁咖啡 class Latte extends Coffee { public Latte() { description = "Latte"; } @Override public double cost() { return 2.5; } } 3. 定义装饰器基类 然后,我们定义一个装饰器基类,它继承自咖啡基类,并持有一个咖啡对象的引用。 java // 咖啡装饰器基类 abstract class CoffeeDecorator extends Coffee { protected Coffee coffee; public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; } @Override public String getDescription() { return coffee.getDescription(); } @Override public double cost() { return coffee.cost(); } } 4. 定义具体的装饰器类 现在,我们可以定义具体的装饰器类了,比如添加牛奶和摩卡酱的装饰器。 java // 添加牛奶的装饰器 class Milk extends CoffeeDecorator { public Milk(Coffee coffee) { super(coffee); } @Override public String getDescription() { return coffee.getDescription() + ", Milk"; } @Override public double cost() { return coffee.cost() + 0.3; } } // 添加摩卡酱的装饰器 class Mocha extends CoffeeDecorator { public Mocha(Coffee coffee) { super(coffee); } @Override public String getDescription() { return coffee.getDescription() + ", Mocha"; } @Override public double cost() { return coffee.cost() + 0.5; } } |
| 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责处理那些可以撤销的职责。 当不能采用生成子类的方式进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是,由于类定义被隐藏,或类定义不能用于生成子类。 | 定义咖啡基类 首先,我们定义一个咖啡基类,它有一个方法用于获取咖啡的描述。 java // 咖啡基类 abstract class Coffee { String description = "Unknown Coffee"; // 获取咖啡描述 public String getDescription() { return description; } // 定义一个方法来准备咖啡(抽象方法,具体咖啡类型会实现它) public abstract double cost(); } 2. 定义具体的咖啡类 接着,我们定义几个具体的咖啡类,比如美式咖啡和拿铁咖啡。 java // 美式咖啡 class Americano extends Coffee { public Americano() { description = "Americano"; } @Override public double cost() { return 1.5; } } // 拿铁咖啡 class Latte extends Coffee { public Latte() { description = "Latte"; } @Override public double cost() { return 2.5; } } 3. 定义装饰器基类 然后,我们定义一个装饰器基类,它继承自咖啡基类,并持有一个咖啡对象的引用。 java // 咖啡装饰器基类 abstract class CoffeeDecorator extends Coffee { protected Coffee coffee; public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; } @Override public String getDescription() { return coffee.getDescription(); } @Override public double cost() { return coffee.cost(); } } 4. 定义具体的装饰器类 现在,我们可以定义具体的装饰器类了,比如添加牛奶和摩卡酱的装饰器。 java // 添加牛奶的装饰器 class Milk extends CoffeeDecorator { public Milk(Coffee coffee) { super(coffee); } @Override public String getDescription() { return coffee.getDescription() + ", Milk"; } @Override public double cost() { return coffee.cost() + 0.3; } } // 添加摩卡酱的装饰器 class Mocha extends CoffeeDecorator { public Mocha(Coffee coffee) { super(coffee); } @Override public String getDescription() { return coffee.getDescription() + ", Mocha"; } @Override public double cost() { return coffee.cost() + 0.5; } } | |
| 外观模式(Facade) | 为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 | ![]() | Facade 模式适用于: 要为一个复杂子系统提供一个简单接口时,子系统往往因为不断演化而变得 杂。大多数模式使用时都会产生更多更小的类,这使得子系统更具有可重用容易对子系统进行定制,但也给那些不需要定制子系统的用户带来一些使用上Facade 可以提供一个简单的默认视图,这一视图对大多数用户来说已经足够,需要更多的可定制性的用户可以越过 Facade 层。客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。 |
| Facade 模式适用于: 要为一个复杂子系统提供一个简单接口时,子系统往往因为不断演化而变得 杂。大多数模式使用时都会产生更多更小的类,这使得子系统更具有可重用容易对子系统进行定制,但也给那些不需要定制子系统的用户带来一些使用上Facade 可以提供一个简单的默认视图,这一视图对大多数用户来说已经足够,需要更多的可定制性的用户可以越过 Facade 层。客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。 | |||
| 享元模式(Flyweight) | 运用共享技术有效地支持大量细粒度的对象。 | ![]() | Flyweight 模式适用于: 个应用程序使用了大量的对象。 完全由于使用大量的对象,造成很大的存储开销。 对象的大多数状态都可变为外部状态。 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,所以对于概念上有别的对象,标识测试将返回真值。 |
| Flyweight 模式适用于: 个应用程序使用了大量的对象。 完全由于使用大量的对象,造成很大的存储开销。 对象的大多数状态都可变为外部状态。 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,所以对于概念上有别的对象,标识测试将返回真值。 | |||
| 代理模式(Proxy) | 为其他对象提供一种代理以控制对这个对象的访问。 | ![]() | 适用性 模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候、常见情况有运程代理(Remote Proxy)为一个对象在不同地址空间提供局部代表。虚代理(Virtual Proxy)根据需要创建开销很大的对象。 保护代理(Protection Proxy)控制对原始对象的访问,用于对象应该有不同的访间权限的时候。 智能引用(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,可以被自动释放;当第一次引用一个持久对象时,将它装入内存;在访间一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。 |
| 适用性 模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候、常见情况有运程代理(Remote Proxy)为一个对象在不同地址空间提供局部代表。虚代理(Virtual Proxy)根据需要创建开销很大的对象。 保护代理(Protection Proxy)控制对原始对象的访问,用于对象应该有不同的访间权限的时候。 智能引用(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,可以被自动释放;当第一次引用一个持久对象时,将它装入内存;在访间一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。 | |||
| 行为型模式(Behavioral Patterns) | 责任链模式(Chain of Responsibility) | 为请求的发送者和接收者之间解耦,使多个对象都有机会处理这个请求,或者将这个请求传递给链中的下一个对象。 | ![]() |
| ||||
| 命令模式(Command) | 将一个请求封装为一个对象,从而使你可用不同的请求、队列、日志来参数化其他对象。命令模式也支持可撤销的操作。 | ![]() |
| |||||
| 解释器模式(Interpreter) | 给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。 | ![]() |
| |||||
| 迭代器模式(Iterator) | 提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。 | ![]() |
| |||||
| 中介者模式(Mediator) | 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 | ![]() |
| |||||
| 备忘录模式(Memento) | 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 | ![]() |
| |||||
| 观察者模式(Observer) | 定义对象间的一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。 | ![]() |
| |||||
| 状态模式(State) | 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 | ![]() |
| |||||
| 策略模式(Strategy) | 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式让算法的变化独立于使用算法的客户。 | ![]() |
| |||||
| 模板方法模式(Template Method) | 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 | ![]() |
| |||||
| 访问者模式(Visitor) | 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 | ![]() |
| |||||
设计模式学习
于 2024-09-20 14:38:16 首次发布













































5292

被折叠的 条评论
为什么被折叠?



