简单工厂模式
简单工厂模式是一种常用的创建型设计模式,它提供了一种创建对象的最佳方式,而不需要暴露对象创建的逻辑给客户端。简单工厂模式的核心思想是将对象的创建和使用分离,从而提高系统的灵活性和可扩展性。
简单工厂模式通常涉及以下几个角色:
- 工厂类(Factory):负责创建产品对象的工厂类。
- 产品接口(Product Interface):所有具体产品类的父接口或父类。
- 具体产品类(Concrete Product):实现了产品接口的具体产品类。
简单工厂模式的优点包括:
- 封装性:将对象的创建和使用分离,客户端不需要知道对象创建的细节。
- 扩展性:增加新的产品类时,只需要修改工厂类的逻辑,客户端代码不需要改动。
缺点包括:
- 工厂类职责过重:如果产品类很多,工厂类的逻辑会变得复杂,难以维护。
- 违反开闭原则:当需要添加新的产品类时,需要修改工厂类的代码,这违反了开闭原则。
示例:实现两个数的运算
抽象操作类
abstract class Operation{
abstract public double getResult(double a, double b);
}
class Add extends Operation{
@Override
public double getResult(double a, double b) {
return a + b;
}
}
class Sub extends Operation{
@Override
public double getResult(double a, double b) {
return a - b;
}
}
class Mul extends Operation{
@Override
public double getResult(double a, double b) {
return a * b;
}
}
class Div extends Operation{
@Override
public double getResult(double a, double b) {
if (b == 0){
throw new ArithmeticException("Division by zero");
}
return a / b;
}
}
简单操作工厂类
class OperationFactory{
public static Operation createOperate(String operate){
Operation operation = null;
switch(operate){
case "+":
operation = new Add();
break;
case "-":
operation = new Sub();
break;
case "*":
operation = new Mul();
break;
case "/":
operation = new Div();
break;
}
return operation;
}
}
主体程序
Scanner sc = new Scanner(System.in);
double numberA = sc.nextDouble();
double numberB = sc.nextDouble();
String strOperation = sc.next();
Operation operation = OperationFactory.createOperate(strOperation);
double result = operation.getResult(numberA, numberB);
System.out.println(result);
策略模式
策略模式是一种行为设计模式,它允许你在运行时选择算法族中的一个算法来执行。通过将算法封装在独立的对象中,策略模式使得算法的变化独立于使用算法的客户。这样可以提高代码的灵活性和可扩展性。
策略模式通常涉及以下几个角色:
- 策略接口(Strategy):定义了所有支持的算法的公共接口。
- 具体策略类(Concrete Strategy):实现了策略接口,提供了具体的算法实现。
- 上下文类(Context):使用策略接口来调用具体的策略对象。
策略模式的优点包括:
- 灵活性:可以在运行时动态地选择和切换算法。
- 扩展性:增加新的策略类时,不需要修改现有的代码,符合开闭原则。
- 解耦:策略类和上下文类之间松耦合,使得代码更容易理解和维护。
策略模式的缺点包括:
- 增加类的数量:每种策略都需要一个具体的类来实现,可能会导致类的数量增多。
- 客户端需要了解策略:客户端需要知道有哪些策略可供选择,并且需要手动设置策略。
示例:模拟超市收银
策略接口
abstract class CashSuper{
abstract public double getResult(double price, int num);
}
具体策略类
class CashNormal extends CashSuper{
@Override
public double getResult(double price, int num) {
return price * num;
}
}
class CashRebate extends CashSuper{
double rate;
CashRebate(double rate){
this.rate = rate;
}
@Override
public double getResult(double price, int num){
return price * num * rate;
}
}
class CashReturn extends CashSuper{
double moneyCondition;
double moneyReturn;
CashReturn(double moneyCondition, double moneyReturn){
this.moneyCondition = moneyCondition;
this.moneyReturn = moneyReturn;
}
@Override
public double getResult(double price, int num) {
double res = price * num;
res -= Math.floor(res / moneyCondition) * moneyReturn;
return res;
}
}
上下文类
class Context{
CashSuper cashSuper;
Context(int cashType){
switch (cashType){
case 1:
cashSuper = new CashNormal();
break;
case 2:
cashSuper = new CashRebate(0.8d);
break;
case 3:
cashSuper = new CashReturn(300, 100);
break;
default:
break;
}
}
public double getResult(double price, int num){
return cashSuper.getResult(price, num);
}
}
主体程序
Scanner sc = new Scanner(System.in);
double price = sc.nextDouble();
int num = sc.nextInt();
Context context = new Context(1);
double res = context.getResult(price, num);
System.out.println(res);
sc.close();
装饰模式
装饰模式是一种结构型设计模式,它允许你在不改变对象接口的情况下,动态地给对象添加新的行为。通过将对象包装在装饰类中,可以在运行时动态地增加对象的功能,而无需修改原有代码。装饰模式特别适用于需要在运行时扩展对象功能的场景。
装饰模式通常涉及以下几个角色:
- 组件接口(Component):定义了对象的基本行为和属性。
- 具体组件类(Concrete Component):实现了组件接口,提供了基本的行为。
- 装饰类(Decorator):持有一个组件对象的引用,并实现组件接口。装饰类可以在组件的基础上添加新的行为。
- 具体装饰类(Concrete Decorator):继承自装饰类,提供了具体的装饰行为。
装饰模式的优点包括:
- 灵活性:可以在运行时动态地添加功能,而不需要修改原有的代码。
- 扩展性:新增功能时,只需要添加新的装饰类,而不必修改现有类。
- 遵循开闭原则:装饰模式使得系统更加灵活,符合开闭原则(对扩展开放,对修改关闭)。
装饰模式的缺点包括:
- 增加类的数量:每种装饰都需要一个具体的类来实现,可能会导致类的数量增多。
- 复杂性增加:过度使用装饰模式可能会使代码变得复杂,难以理解和维护。
示例:穿衣服
组件接口
interface Character{
public void show();
}
具体组件类
class Person implements Character{
String name;
Person(String name){
this.name = name;
}
@Override
public void show(){
System.out.println("装扮的" + name);
}
}
装饰类
class Decorator implements Character{
protected Character component;
public void decorator(Character character){
this.component = character;
}
@Override
public void show(){
component.show();
}
}
具体装饰类
class TShirts extends Decorator{
@Override
public void show(){
System.out.print("大T恤 ");
super.show();
}
}
class BigTrouser extends Decorator{
@Override
public void show(){
System.out.print("垮裤 ");
super.show();
}
}
主体程序
Person p = new Person("张三");
TShirts t = new TShirts();
t.decorator(p);
BigTrouser b = new BigTrouser();
b.decorator(t);
b.show();
代理模式
代理模式是一种结构型设计模式,它允许你提供一个代理对象来控制对另一个对象的访问。代理模式可以在不改变原始对象接口的情况下,增加额外的功能或控制访问。代理模式常用于延迟初始化、权限控制、远程访问等场景。
代理模式通常涉及以下几个角色:
- 主题接口(Subject):定义了真实对象和代理对象的共同接口,确保代理对象可以替代真实对象使用。
- 真实对象(Real Subject):实现了主题接口,提供了具体的业务逻辑。
- 代理对象(Proxy):也实现了主题接口,持有对真实对象的引用,并在调用真实对象的方法前后可以添加额外的操作。
代理模式的优点包括:
- 延迟初始化:可以在需要时才加载资源,提高性能。
- 权限控制:可以在访问真实对象之前进行权限检查。
- 远程访问:可以隐藏真实对象的实现细节,提供远程访问的能力。
- 日志记录:可以在调用真实对象的方法前后记录日志。
- 智能引用:可以在访问真实对象时进行额外的处理,如缓存、统计等。
代理模式的缺点包括:
- 增加类的数量:每个真实对象都需要一个对应的代理对象,可能会导致类的数量增多。
- 复杂性增加:过度使用代理模式可能会使代码变得复杂,难以理解和维护。
示例:图像懒加载
主题接口
public interface Image {
void display();
}
真实对象
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}
private void loadFromDisk(String fileName) {
System.out.println("Loading image from disk: " + fileName);
}
@Override
public void display() {
System.out.println("Displaying image: " + fileName);
}
}
代理对象
public class ImageProxy implements Image {
private String fileName;
private RealImage realImage;
public ImageProxy(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
// 预先对图片的地址赋值给一个图像进行占位,当需要的时候就执行下面的函数,加载真正的图片
realImage.display();
}
}
主体程序
Image image1 = new ImageProxy("image1.jpg");
Image image2 = new ImageProxy("image2.jpg");
image1.display();
image2.display();
// 再次调用 display 方法时,不会重新加载图像
image1.display();
image2.display();
工厂方法模式
工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法模式将对象的创建推迟到子类,从而使得系统更加灵活和可扩展。
工厂方法模式通常涉及以下几个角色:
- 产品接口(Product Interface):定义了所有具体产品类的公共接口。
- 具体产品类(Concrete Product):实现了产品接口,提供了具体的实现。
- 工厂接口(Creator Interface):定义了创建产品的接口。
- 具体工厂类(Concrete Creator):实现了工厂接口,负责创建具体的产品对象。
工厂方法模式的优点
- 扩展性:增加新的产品类时,只需要添加新的具体工厂类,而不需要修改现有的代码,符合开闭原则。
- 多态性:客户端代码可以通过工厂接口来创建对象,而不需要关心具体的实现,提高了代码的灵活性。
- 解耦:将对象的创建和使用分离,降低了模块间的耦合度。
工厂方法模式的缺点
- 增加类的数量:每种产品都需要一个具体的工厂类来创建,可能会导致类的数量增多。
- 复杂性增加:相对于简单工厂模式,工厂方法模式的类结构更加复杂,可能会增加系统的复杂性。
产品接口
public interface Car {
void drive();
}
具体产品类
public class SUV implements Car {
@Override
public void drive() {
System.out.println("Driving an SUV car.");
}
}
public class BWM implements Car {
@Override
public void drive() {
System.out.println("Driving a bwm car.");
}
}
工厂接口
public interface CarFactory {
Car createCar();
}
具体工厂类
public class SUVFactory implements CarFactory {
@Override
public Car createCar() {
return new SUV();
}
}
public class BWMFactory implements CarFactory {
@Override
public Car createCar() {
return new BWM();
}
}
主体程序
// 创建 BWM 工厂并使用它来创建 BWM 对象
CarFactory bwmFactory = new BWMFactory();
Car bwm = bwmFactory.createCar();
bwm.drive(); // 输出: Driving a sedan car.
// 创建 SUV 工厂并使用它来创建 SUV 对象
CarFactory suvFactory = new SUVFactory();
Car suv = suvFactory.createCar();
suv.drive(); // 输出: Driving an SUV car.
原型模式
原型模式是一种创建型设计模式,它允许你通过复制现有的对象来创建新对象,而不需要通过构造函数来创建。这种方式可以简化对象的创建过程,特别是当对象的创建过程比较复杂或耗时时。
原型模式通常涉及以下几个角色:
- 原型接口(Prototype):定义了一个克隆自身的接口。
- 具体原型类(Concrete Prototype):实现了原型接口,提供具体的克隆方法。
- 客户端(Client):使用原型接口来复制对象。
原型模式的优点
- 性能提升:通过复制现有对象而不是创建新对象,可以提高性能,特别是在对象创建过程复杂或耗时的情况下。
- 减少重复代码:减少了创建新对象时的重复代码,特别是当对象的初始化过程很复杂时。
- 灵活性:可以在运行时动态地添加或删除对象,而不需要修改现有代码。
原型模式的缺点
- 深拷贝复杂:实现深拷贝可能需要更多的代码和复杂性,特别是当对象包含多个层次的嵌套对象时。
- 类必须实现 Cloneable 接口:所有需要克隆的对象都必须实现
Cloneable
接口,并且重写clone
方法。
原型接口
public interface DocumentPrototype {
// 这个接口感觉主要是用来存对象的,通过共同的父类保存子类的信息,
// 然后再向下转型,恢复子类信息
DocumentPrototype clone();
}
具体原型类
import java.util.HashMap;
import java.util.Map;
public class Document implements DocumentPrototype {
private String name;
private Map<String, String> content;
public Document(String name) {
this.name = name;
this.content = new HashMap<>();
}
public void addContent(String key, String value) {
content.put(key, value);
}
public String getContent(String key) {
return content.get(key);
}
@Override
public DocumentPrototype clone() {
// 浅拷贝
try {
return (DocumentPrototype) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
// 深拷贝
//try {
// Document clonedDocument = (Document) super.clone();
// clonedDocument.content = new HashMap<>(this.content);
// return clonedDocument;
//} catch (CloneNotSupportedException e) {
// throw new RuntimeException(e);
//}
}
@Override
public String toString() {
return "Document{" +
"name='" + name + '\'' +
", content=" + content +
'}';
}
}
主体程序
// 创建一个原始文档对象
Document originalDocument = new Document("Original Document");
originalDocument.addContent("Section 1", "This is the first section.");
originalDocument.addContent("Section 2", "This is the second section.");
System.out.println("Original Document: " + originalDocument);
// 复制原始文档对象
Document clonedDocument = originalDocument.clone();
System.out.println("Cloned Document: " + clonedDocument);
// 修改克隆文档的内容
clonedDocument.addContent("Section 3", "This is the third section.");
System.out.println("Modified Cloned Document: " + clonedDocument);
模板方法模式
模板方法模式是一种行为设计模式,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。这样,子类可以重新定义算法的某些步骤,而不会改变算法的整体结构。
模板方法模式通常涉及以下几个角色:
- 抽象类(Abstract Class):定义了一个或多个抽象方法,这些方法由子类实现。同时,定义了一个模板方法,该方法定义了算法的骨架。
- 具体类(Concrete Class):继承自抽象类,实现抽象方法,完成具体的步骤。
模板方法模式的优点
- 代码复用:通过定义模板方法,可以将公共部分的代码提取到抽象类中,减少代码重复。
- 扩展性:子类可以通过实现抽象方法来扩展具体的步骤,而不会改变算法的整体结构。
- 封装性:模板方法封装了算法的骨架,使得客户端代码不需要关心具体的实现细节。
模板方法模式的缺点
- 子类实现细节:每个子类都需要实现抽象方法,增加了子类的负担。
- 继承带来的缺点:过度使用继承可能导致类层次结构复杂,难以维护。
示例:游戏
抽象类
public abstract class Game {
// 模板方法,定义了游戏的骨架
public final void play() {
initialize();
startPlay();
endPlay();
}
// 抽象方法,由子类实现
protected abstract void initialize();
// 抽象方法,由子类实现
protected abstract void startPlay();
// 抽象方法,由子类实现
protected abstract void endPlay();
}
具体类
public class Football extends Game {
@Override
protected void initialize() {
System.out.println("Football game is initializing...");
}
@Override
protected void startPlay() {
System.out.println("Football game is starting...");
}
@Override
protected void endPlay() {
System.out.println("Football game is ending...");
}
}
public class Basketball extends Game {
@Override
protected void initialize() {
System.out.println("Basketball game is initializing...");
}
@Override
protected void startPlay() {
System.out.println("Basketball game is starting...");
}
@Override
protected void endPlay() {
System.out.println("Basketball game is ending...");
}
}
主体程序
// 创建并运行足球游戏
Game footballGame = new Football();
footballGame.play();
// 创建并运行篮球游戏
Game basketballGame = new Basketball();
basketballGame.play();
外观模式
外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口来访问子系统中的一组功能,从而简化了高层模块对子系统的使用。外观模式通过隐藏子系统的复杂性,使客户端代码更加简洁和易于维护。
外观模式通常涉及以下几个角色:
- 子系统类(Subsystem Classes):实现了子系统的具体功能。
- 外观类(Facade):提供了一个简化的接口,客户端通过这个接口来访问子系统的功能。
- 客户端(Client):通过外观类来调用子系统的功能。
外观模式的优点
- 简化接口:通过提供一个简化的接口,客户端代码可以更方便地访问子系统的功能,而不需要了解子系统的内部细节。
- 降低耦合度:客户端与子系统的耦合度降低,因为客户端只与外观类交互,而不直接与子系统类交互。
- 更好的分层:外观模式可以帮助实现分层结构,使得系统更加模块化和易于维护。
外观模式的缺点
- 增加类的数量:引入外观类会增加系统的类数量,可能会使系统结构稍微复杂一些。
- 限制灵活性:客户端只能通过外观类提供的接口来访问子系统,可能会限制客户端对子系统的直接访问。
子系统类
public class AudioPlayer {
public void playAudio(String audioFile) {
System.out.println("Playing audio file: " + audioFile);
}
}
public class VideoPlayer {
public void playVideo(String videoFile) {
System.out.println("Playing video file: " + videoFile);
}
}
public class MediaLibrary {
public void listMediaFiles() {
System.out.println("Listing media files...");
System.out.println("1. song.mp3");
System.out.println("2. movie.mp4");
}
}
外观类
public class MediaPlayerFacade {
private AudioPlayer audioPlayer;
private VideoPlayer videoPlayer;
private MediaLibrary mediaLibrary;
public MediaPlayerFacade() {
this.audioPlayer = new AudioPlayer();
this.videoPlayer = new VideoPlayer();
this.mediaLibrary = new MediaLibrary();
}
public void playAudio(String audioFile) {
audioPlayer.playAudio(audioFile);
}
public void playVideo(String videoFile) {
videoPlayer.playVideo(videoFile);
}
public void listMediaFiles() {
mediaLibrary.listMediaFiles();
}
}
主体程序
// 创建外观对象
MediaPlayerFacade mediaPlayer = new MediaPlayerFacade();
// 列出媒体文件
mediaPlayer.listMediaFiles();
// 播放音频文件
mediaPlayer.playAudio("song.mp3");
// 播放视频文件
mediaPlayer.playVideo("movie.mp4");
建造者模式
建造者模式(Builder Pattern)是一种创建型设计模式,它允许你逐步构建复杂的对象,而不需要使用大量的构造函数参数。建造者模式的主要目的是分离对象的构造过程和表示,使得相同的构造过程可以创建不同的表示。
建造者模式通常涉及以下几个角色:
- 产品类(Product):要创建的复杂对象。
- 抽象建造者(Abstract Builder):定义了创建产品各个部分的方法。
- 具体建造者(Concrete Builder):实现了抽象建造者接口,负责构建和装配各个部件。
- 导演类(Director):使用具体建造者来构建产品的各个部分,通常不依赖于具体的产品类。
建造者模式的优点
- 分离构建和表示:建造者模式将对象的构建过程和表示分离,使得相同的构建过程可以创建不同的表示。
- 减少构造函数参数:避免了使用大量构造函数参数的情况,使得对象的创建过程更加清晰和灵活。
- 更好的代码可读性和可维护性:通过逐步构建对象,代码更加清晰和易于维护。
建造者模式的缺点
- 增加类的数量:引入建造者类会增加系统的类数量,可能会使系统结构稍微复杂一些。
- 灵活性有限:建造者模式的灵活性受到建造者接口的限制,如果需要添加新的构建步骤,可能需要修改接口。
产品类
public class Meal {
private String mainCourse;
private String drink;
private String dessert;
public void setMainCourse(String mainCourse) {
this.mainCourse = mainCourse;
}
public void setDrink(String drink) {
this.drink = drink;
}
public void setDessert(String dessert) {
this.dessert = dessert;
}
@Override
public String toString() {
return "Meal{" +
"mainCourse='" + mainCourse + '\'' +
", drink='" + drink + '\'' +
", dessert='" + dessert + '\'' +
'}';
}
}
抽象建造者
public interface MealBuilder {
void buildMainCourse();
void buildDrink();
void buildDessert();
Meal getMeal();
}
具体建造者
public class VegetarianMealBuilder implements MealBuilder {
private Meal meal;
public VegetarianMealBuilder() {
this.meal = new Meal();
}
@Override
public void buildMainCourse() {
meal.setMainCourse("Vegetable Stir-Fry");
}
@Override
public void buildDrink() {
meal.setDrink("Fresh Juice");
}
@Override
public void buildDessert() {
meal.setDessert("Fruit Salad");
}
@Override
public Meal getMeal() {
return meal;
}
}
public class NonVegetarianMealBuilder implements MealBuilder {
private Meal meal;
public NonVegetarianMealBuilder() {
this.meal = new Meal();
}
@Override
public void buildMainCourse() {
meal.setMainCourse("Grilled Chicken");
}
@Override
public void buildDrink() {
meal.setDrink("Soda");
}
@Override
public void buildDessert() {
meal.setDessert("Chocolate Cake");
}
@Override
public Meal getMeal() {
return meal;
}
}
导演类
public class Waiter {
public void constructMeal(MealBuilder builder) {
builder.buildMainCourse();
builder.buildDrink();
builder.buildDessert();
}
}
主体程序
// 创建导演对象
Waiter waiter = new Waiter();
// 创建素食餐点
MealBuilder vegetarianBuilder = new VegetarianMealBuilder();
waiter.constructMeal(vegetarianBuilder);
Meal vegetarianMeal = vegetarianBuilder.getMeal();
System.out.println("Vegetarian Meal: " + vegetarianMeal);
// 创建非素食餐点
MealBuilder nonVegetarianBuilder = new NonVegetarianMealBuilder();
waiter.constructMeal(nonVegetarianBuilder);
Meal nonVegetarianMeal = nonVegetarianBuilder.getMeal();
System.out.println("Non-Vegetarian Meal: " + nonVegetarianMeal);
观察者模式
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。观察者模式的核心思想是将对象之间的依赖关系从紧耦合变为松耦合,从而提高系统的灵活性和可扩展性。
观察者模式通常涉及以下几个角色:
- 主题(Subject):也称为被观察者,它维护一个观察者的列表,并提供添加、删除和通知观察者的方法。
- 观察者(Observer):定义了一个更新接口,当主题的状态发生变化时,观察者会被通知并调用这个接口。
- 具体主题(Concrete Subject):实现主题接口,维护状态信息,并在状态变化时通知观察者。
- 具体观察者(Concrete Observer):实现观察者接口,存储状态信息,并在接收到通知时更新自己的状态。
观察者模式的优点
- 松耦合:观察者和主题之间的依赖关系是松耦合的,观察者只需要实现观察者接口,而不需要知道主题的具体实现。
- 扩展性:可以轻松地添加新的观察者,而不需要修改现有代码。
- 灵活性:观察者可以动态地注册和注销,使得系统更加灵活和可扩展。
观察者模式的缺点
- 依赖关系复杂:随着观察者的增多,依赖关系可能会变得复杂,需要仔细管理。
- 更新顺序不可控:观察者之间的更新顺序无法保证,可能会导致意外的行为。
主题
import java.util.ArrayList;
import java.util.List;
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
public class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public void measurementsChanged() {
notifyObservers();
}
}
观察者
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
主体程序
// 创建具体主题
WeatherData weatherData = new WeatherData();
// 创建具体观察者
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
// 注册观察者
weatherData.registerObserver(currentDisplay);
// 更新天气数据
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建一组相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式的主要目的是确保创建的对象家族具有一致性,使得客户端代码可以独立于具体类的实现。
抽象工厂模式通常涉及以下几个角色:
- 抽象工厂(Abstract Factory):定义了一个创建一组相关或相互依赖对象的接口。
- 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体的产品对象。
- 抽象产品(Abstract Product):定义了一组产品对象的接口。
- 具体产品(Concrete Product):实现了抽象产品接口,具体工厂创建的对象。
抽象工厂模式的优点
- 分离接口和实现:客户端代码只依赖于抽象工厂和抽象产品接口,而不需要知道具体类的实现。
- 易于扩展:添加新的产品族时,只需添加新的具体工厂和具体产品类,而不需要修改现有代码。
- 确保一致性:确保创建的对象家族具有一致性,避免了对象之间的不兼容问题。
抽象工厂模式的缺点
- 系统复杂性增加:引入了多个抽象类和具体类,使得系统结构变得更加复杂。
- 具体工厂的依赖:客户端代码需要选择具体工厂,这可能会导致依赖关系的增加。
产品
public interface Button {
void paint();
}
public interface Textbox {
void paint();
}
// Windows 风格的按钮
public class WindowsButton implements Button {
@Override
public void paint() {
System.out.println("Painting a Windows button");
}
}
// Mac 风格的按钮
public class MacButton implements Button {
@Override
public void paint() {
System.out.println("Painting a Mac button");
}
}
// Windows 风格的文本框
public class WindowsTextbox implements Textbox {
@Override
public void paint() {
System.out.println("Painting a Windows textbox");
}
}
// Mac 风格的文本框
public class MacTextbox implements Textbox {
@Override
public void paint() {
System.out.println("Painting a Mac textbox");
}
}
工厂
public interface GUIFactory {
Button createButton();
Textbox createTextbox();
}
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public Textbox createTextbox() {
return new WindowsTextbox();
}
}
public class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public Textbox createTextbox() {
return new MacTextbox();
}
}
主体程序
// 创建具体工厂
GUIFactory factory;
// 根据需要选择不同的工厂
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
factory = new WindowsFactory();
} else {
factory = new MacFactory();
}
// 创建并使用按钮和文本框
Button button = factory.createButton();
Textbox textbox = factory.createTextbox();
button.paint();
textbox.paint();
状态模式
状态模式(State Pattern)是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。状态模式将对象的行为封装在不同的状态类中,使得状态转换更加清晰和灵活。通过这种方式,可以避免在状态变化时出现大量的条件判断语句,从而使代码更加简洁和易于维护。
状态模式通常涉及以下几个角色:
- 环境类(Context):维护一个当前状态对象的引用,并提供接口供客户端调用。
- 抽象状态类(State):定义了一个接口,用于封装与环境类的一个特定状态相关的行为。
- 具体状态类(Concrete State):实现了抽象状态类接口,定义了具体的状态行为。
状态模式的优点
- 封装变化:将不同的行为封装在不同的状态类中,使得状态转换更加清晰和灵活。
- 减少条件判断:避免了在状态变化时出现大量的条件判断语句,使代码更加简洁和易于维护。
- 扩展性:添加新的状态和行为时,只需要添加新的状态类,而不需要修改现有的代码。
状态模式的缺点
- 类数量增加:每个状态都需要一个具体的类,可能会增加系统的类数量。
- 复杂性增加:对于简单的状态转换,使用状态模式可能会显得过于复杂。
环境类
public class TextEditor {
private State state;
public TextEditor(State state) {
this.state = state;
}
public void setState(State state) {
this.state = state;
}
public void pressEditButton() {
state.handleEdit(this);
}
public void pressViewButton() {
state.handleView(this);
}
public void pressNormalButton() {
state.handleNormal(this);
}
}
状态类
public interface State {
void handleEdit(TextEditor editor);
void handleView(TextEditor editor);
void handleNormal(TextEditor editor);
}
public class NormalState implements State {
@Override
public void handleEdit(TextEditor editor) {
System.out.println("Switching to Edit mode");
editor.setState(new EditState());
}
@Override
public void handleView(TextEditor editor) {
System.out.println("Switching to View mode");
editor.setState(new ViewState());
}
@Override
public void handleNormal(TextEditor editor) {
System.out.println("Already in Normal mode");
}
}
public class EditState implements State {
@Override
public void handleEdit(TextEditor editor) {
System.out.println("Already in Edit mode");
}
@Override
public void handleView(TextEditor editor) {
System.out.println("Switching to View mode");
editor.setState(new ViewState());
}
@Override
public void handleNormal(TextEditor editor) {
System.out.println("Switching to Normal mode");
editor.setState(new NormalState());
}
}
public class ViewState implements State {
@Override
public void handleEdit(TextEditor editor) {
System.out.println("Switching to Edit mode");
editor.setState(new EditState());
}
@Override
public void handleView(TextEditor editor) {
System.out.println("Already in View mode");
}
@Override
public void handleNormal(TextEditor editor) {
System.out.println("Switching to Normal mode");
editor.setState(new NormalState());
}
}
主体程序
// 创建初始状态为普通模式的文本编辑器
State initialState = new NormalState();
TextEditor editor = new TextEditor(initialState);
// 用户按下编辑按钮
editor.pressEditButton();
// 用户按下查看按钮
editor.pressViewButton();
// 用户再次按下编辑按钮
editor.pressEditButton();
// 用户按下普通按钮
editor.pressNormalButton();
适配器模式
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换成客户端期望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。适配器模式有两种主要形式:类适配器和对象适配器。
适配器模式通常涉及以下几个角色:
- 目标接口(Target):定义客户端所期望的接口。
- 适配者(Adaptee):已经存在的类,但其接口与目标接口不兼容。
- 适配器(Adapter):将适配者的接口转换为目标接口,使得客户端可以使用适配者的功能。
适配器模式的优点
- 提高复用性:可以重用已有的类,而不需要修改源代码。
- 增加灵活性:客户端可以使用适配器模式来适配不同的类,而不需要修改客户端代码。
- 分离接口和实现:适配器模式将目标接口和适配者接口分离,使得代码更加清晰和模块化。
适配器模式的缺点
- 类数量增加:引入适配器类会增加系统的类数量,可能会使系统结构稍微复杂一些。
- 理解难度:适配器模式的实现可能会增加代码的理解难度,特别是对于不熟悉该模式的开发者。
对于不能多重继承类的不适用
目标接口
public interface MediaPlayer {
void play(String audioType, String fileName);
}
适配者
public class AdvancedMediaPlayer {
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: " + fileName);
}
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: " + fileName);
}
}
适配器
public class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedMediaPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMediaPlayer = new AdvancedMediaPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMediaPlayer = new AdvancedMediaPlayer();
}
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMediaPlayer.playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMediaPlayer.playMp4(fileName);
} else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
主体程序
public class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: " + fileName);
} else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
if (mediaAdapter == null) {
mediaAdapter = new MediaAdapter(audioType);
}
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("Invalid media. " + audioType + " format not supported");
}
}
}
public class Client {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond_the_horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far远away.vlc");
audioPlayer.play("avi", "mind.midi");
}
}
目标接口
public interface Target {
void request();
}
适配者
public class Adaptee {
public void specificRequest() {
System.out.println("Specific request from Adaptee");
}
}
适配器
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
主体程序
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target adapter = new Adapter(adaptee);
adapter.request();
}
}
备忘录模式
备忘录模式(Memento Pattern)是一种行为设计模式,它用于保存一个对象的内部状态,以便在将来需要时可以恢复到之前的状态。备忘录模式的核心思想是将对象的状态封装在一个独立的备忘录对象中,这样可以在不破坏封装的前提下保存和恢复对象的状态。
备忘录模式通常涉及以下几个角色:
- 发起人(Originator):需要保存内部状态的对象,它负责创建和恢复备忘录对象。
- 备忘录(Memento):用于存储发起人的内部状态,通常是私有的,只有发起人可以访问。
- 管理者(Caretaker):负责保存和管理备忘录对象,但不访问备忘录的具体内容。
备忘录模式的优点
- 保存内部状态:可以保存对象的内部状态,而不暴露对象的实现细节。
- 恢复状态:可以在不破坏封装的前提下恢复对象的内部状态。
- 简化客户端代码:客户端可以通过管理者类来管理备忘录对象,而不需要直接操作备忘录。
备忘录模式的缺点
- 资源消耗:保存大量的备忘录对象可能会占用较多的内存资源。
- 性能影响:频繁的保存和恢复操作可能会影响系统的性能。
发起人
public class TextEditor {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
System.out.println("Content changed to: " + content);
}
public Memento saveToMemento() {
System.out.println("Saving state to memento...");
return new Memento(content);
}
public void restoreFromMemento(Memento memento) {
System.out.println("Restoring state from memento...");
content = memento.getContent();
System.out.println("Content restored to: " + content);
}
}
备忘录
public class Memento {
private final String content;
public Memento(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
管理者
import java.util.ArrayList;
import java.util.List;
public class Caretaker {
private List<Memento> mementoList = new ArrayList<>();
public void addMemento(Memento memento) {
mementoList.add(memento);
}
public Memento getMemento(int index) {
return mementoList.get(index);
}
}
主体程序
public class Client {
public static void main(String[] args) {
TextEditor textEditor = new TextEditor();
Caretaker caretaker = new Caretaker();
// 初始内容
textEditor.setContent("Hello, World!");
// 保存状态
caretaker.addMemento(textEditor.saveToMemento());
// 修改内容
textEditor.setContent("Hello, Java!");
// 再次保存状态
caretaker.addMemento(textEditor.saveToMemento());
// 修改内容
textEditor.setContent("Hello, Python!");
// 恢复到第一个状态
textEditor.restoreFromMemento(caretaker.getMemento(0));
// 恢复到最后一个状态
textEditor.restoreFromMemento(caretaker.getMemento(1));
}
}
组合模式
组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构以表示“部分-整体”的层次关系。组合模式使得客户端可以统一地对待单个对象和组合对象,从而简化客户端代码的设计和实现。
组合模式通常涉及以下几个角色:
- 组件(Component):定义了树中每个节点的行为,既可以是叶子节点,也可以是组合节点。它声明了所有子类共有的接口。
- 叶子(Leaf):表示叶子节点,没有子节点,实现组件接口。
- 组合(Composite):表示组合节点,可以包含子节点,实现组件接口,并管理子节点的集合。
- 客户端(Client):通过组件接口与组合结构中的对象交互。
组合模式的优点
- 透明性:客户端可以一致地对待单个对象和组合对象,简化了客户端代码的设计和实现。
- 灵活性:可以轻松地添加新的叶子节点和组合节点,而不需要修改现有代码。
- 层次结构:可以方便地构建和管理树形结构,适用于表示具有层次关系的对象。
组合模式的缺点
- 复杂性增加:引入了多个类和接口,可能会增加系统的复杂性。
- 性能影响:遍历组合结构时可能会有一定的性能开销,特别是在树形结构较深的情况下。
组件接口
public interface Component {
void operation();
}
叶子
public class File implements Component {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void operation() {
System.out.println("Opening file: " + name);
}
}
组合
import java.util.ArrayList;
import java.util.List;
public class Directory implements Component {
private String name;
private List<Component> children = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
public List<Component> getChildren() {
return children;
}
@Override
public void operation() {
System.out.println("Opening directory: " + name);
for (Component child : children) {
child.operation();
}
}
}
主体程序
public class Client {
public static void main(String[] args) {
// 创建文件和目录
File file1 = new File("file1.txt");
File file2 = new File("file2.txt");
Directory dir1 = new Directory("dir1");
Directory dir2 = new Directory("dir2");
// 构建文件系统结构
dir1.add(file1);
dir1.add(file2);
dir2.add(dir1);
dir2.add(new File("file3.txt"));
// 打开目录和文件
dir2.operation();
}
}
迭代器模式
迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种方法来顺序访问一个聚合对象中的各个元素,而不需要暴露其内部的表示。迭代器模式使得客户端可以遍历聚合对象中的元素,而不需要了解聚合对象的内部结构。
迭代器模式通常涉及以下几个角色:
- 聚合(Aggregate):定义了创建迭代器对象的接口。
- 具体聚合(Concrete Aggregate):实现了聚合接口,返回一个具体的迭代器对象。
- 迭代器(Iterator):定义了访问和遍历元素的接口。
- 具体迭代器(Concrete Iterator):实现了迭代器接口,负责访问和遍历聚合对象中的元素。
迭代器模式的优点
- 封装性:迭代器模式将访问和遍历聚合对象的逻辑封装在迭代器对象中,使得客户端代码更加简洁和清晰。
- 灵活性:可以轻松地添加新的迭代器类,而不需要修改现有代码。
- 统一接口:客户端可以通过统一的迭代器接口遍历不同的聚合对象,而不需要了解聚合对象的内部结构。
迭代器模式的缺点
- 增加类的数量:引入了迭代器类和聚合类,可能会增加系统的类数量。
- 性能影响:遍历聚合对象时可能会有一定的性能开销,特别是在集合较大的情况下。
聚合
public interface BookCollection {
Iterator<Book> createIterator();
}
import java.util.ArrayList;
import java.util.List;
public class ConcreteBookCollection implements BookCollection {
private List<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
}
@Override
public Iterator<Book> createIterator() {
return new ConcreteIterator<>(books);
}
}
public interface Iterator<T> {
boolean hasNext();
T next();
}
public class ConcreteIterator<T> implements Iterator<T> {
private List<T> items;
private int position = 0;
public ConcreteIterator(List<T> items) {
this.items = items;
}
@Override
public boolean hasNext() {
return position < items.size();
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items.get(position++);
}
}
元素
public class Book {
private String title;
private String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
@Override
public String toString() {
return "Book{" +
"title='" + title + '\'' +
", author='" + author + '\'' +
'}';
}
}
主体程序
public class Client {
public static void main(String[] args) {
ConcreteBookCollection bookCollection = new ConcreteBookCollection();
bookCollection.addBook(new Book("Effective Java", "Joshua Bloch"));
bookCollection.addBook(new Book("Clean Code", "Robert C. Martin"));
bookCollection.addBook(new Book("Design Patterns", "Erich Gamma et al."));
Iterator<Book> iterator = bookCollection.createIterator();
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println(book);
}
}
}
单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。单例模式的主要目的是控制资源的使用,通过共享唯一的资源来优化系统性能。
单例模式通常涉及以下几个角色:
- 单例类(Singleton):确保一个类只有一个实例,并提供一个全局访问点。
- 客户端(Client):通过单例类提供的全局访问点来访问单例对象。
单例模式的优点
- 唯一性:确保一个类只有一个实例,避免了全局变量带来的问题。
- 控制资源:可以优化系统性能,控制资源的使用。
- 全局访问:提供了一个全局访问点,方便客户端访问单例对象。
单例模式的缺点
- 过度使用:如果过度使用单例模式,可能会导致系统难以测试和维护。
- 线程安全:需要特别注意多线程环境下的线程安全问题。
- 扩展性:单例类的扩展性较差,一旦创建了单例对象,很难对其进行修改。
单例模式有多种实现方式,常见的有以下几种:
- 懒汉式(Lazy Initialization)
- 饿汉式(Eager Initialization)
- 双重检查锁定(Double-Checked Locking)
- 静态内部类(Static Inner Class)
懒汉式
懒汉式在第一次使用时创建单例对象,但在多线程环境下可能会出现问题。
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 synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
通过双重检查锁定来保证线程安全,同时提高效率。
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
线程安全,但提前加载
在类加载时就创建单例对象,线程安全但提前加载。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
通过静态内部类来实现单例,既保证线程安全又延迟加载。
线程安全,延迟加载
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
桥接模式
桥接模式(Bridge Pattern)是一种结构型设计模式,它将一个类的抽象部分与其实现部分分离,使它们可以独立变化。桥接模式的主要目的是将抽象和实现解耦,使得它们可以独立地进行扩展和变化,从而提高系统的灵活性和可维护性。
桥接模式通常涉及以下几个角色:
- 抽象部分(Abstraction):定义了抽象部分的接口,并持有一个对实现部分的引用。
- 细化抽象部分(RefinedAbstraction):扩展了抽象部分,提供了更具体的实现。
- 实现部分(Implementor):定义了实现部分的接口,具体实现类将实现这个接口。
- 具体实现部分(ConcreteImplementor):实现了实现部分接口,提供了具体的实现。
桥接模式的优点
- 分离抽象和实现:将抽象部分和实现部分分离,使得它们可以独立变化,提高了系统的灵活性和可扩展性。
- 减少子类数量:减少了子类的数量,避免了类爆炸的问题。
- 动态切换实现:可以在运行时动态切换实现部分,提供了更高的灵活性。
桥接模式的缺点
- 增加复杂性:引入了更多的类和接口,可能会增加系统的复杂性。
- 客户端复杂度:客户端代码需要管理抽象部分和实现部分的组合,可能会增加客户端的复杂度。
抽象部分
public abstract class Shape {
protected ShapeDrawer drawer;
public Shape(ShapeDrawer drawer) {
this.drawer = drawer;
}
public abstract void draw();
}
细化抽象部分
public class Circle extends Shape {
private int x;
private int y;
private int radius;
public Circle(ShapeDrawer drawer, int x, int y, int radius) {
super(drawer);
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
public void draw() {
drawer.drawCircle(x, y, radius);
}
}
public class Rectangle extends Shape {
private int x;
private int y;
private int width;
private int height;
public Rectangle(ShapeDrawer drawer, int x, int y, int width, int height) {
super(drawer);
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public void draw() {
drawer.drawRectangle(x, y, width, height);
}
}
实现部分
public interface ShapeDrawer {
void drawCircle(int x, int y, int radius);
void drawRectangle(int x, int y, int width, int height);
}
具体实现部分
public class RedShapeDrawer implements ShapeDrawer {
@Override
public void drawCircle(int x, int y, int radius) {
System.out.println("Drawing a red circle at (" + x + ", " + y + ") with radius " + radius);
}
@Override
public void drawRectangle(int x, int y, int width, int height) {
System.out.println("Drawing a red rectangle at (" + x + ", " + y + ") with width " + width + " and height " + height);
}
}
public class BlueShapeDrawer implements ShapeDrawer {
@Override
public void drawCircle(int x, int y, int radius) {
System.out.println("Drawing a blue circle at (" + x + ", " + y + ") with radius " + radius);
}
@Override
public void drawRectangle(int x, int y, int width, int height) {
System.out.println("Drawing a blue rectangle at (" + x + ", " + y + ") with width " + width + " and height " + height);
}
}
主体程序
public class Client {
public static void main(String[] args) {
// 创建绘制器
ShapeDrawer redDrawer = new RedShapeDrawer();
ShapeDrawer blueDrawer = new BlueShapeDrawer();
// 创建形状
Shape redCircle = new Circle(redDrawer, 10, 10, 5);
Shape blueRectangle = new Rectangle(blueDrawer, 20, 20, 10, 15);
// 绘制形状
redCircle.draw();
blueRectangle.draw();
}
}
命令模式
命令模式(Command Pattern)是一种行为设计模式,它将请求封装成对象,从而使你可以用不同的请求、队列或者请求的日志来参数化其他对象。命令模式还可以支持撤销操作。
命令模式通常涉及以下几个角色:
- 命令(Command):定义了声明执行操作的接口。
- 具体命令(Concrete Command):实现了命令接口,负责执行实际的操作。
- 接收者(Receiver):执行具体操作的对象。
- 请求者(Invoker):持有命令对象,并负责调用命令对象的执行方法。
- 客户端(Client):创建命令对象,并将其设置到请求者中。
命令模式的优点
- 解耦:命令模式将请求发送者和接收者解耦,使得两者可以独立变化。
- 扩展性:可以轻松地添加新的命令类,而不需要修改现有代码。
- 支持撤销操作:命令模式可以很容易地支持撤销操作,只需在命令类中实现
undo
方法即可。 - 队列和日志:命令模式可以用于实现命令队列和命令日志,方便管理和恢复操作。
命令模式的缺点
- 增加类的数量:引入了命令类和接收者类,可能会增加系统的类数量。
- 复杂性增加:增加了系统的复杂性,特别是对于简单的请求处理。
命令接口
public interface Command {
void execute();
void undo();
}
具体命令
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
@Override
public void undo() {
light.turnOff();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
@Override
public void undo() {
light.turnOn();
}
}
接收者
public class Light {
private boolean isOn = false;
public void turnOn() {
isOn = true;
System.out.println("Light is on");
}
public void turnOff() {
isOn = false;
System.out.println("Light is off");
}
}
请求者
public class RemoteControl {
private Command onCommand;
private Command offCommand;
private Command undoCommand;
public RemoteControl(Command onCommand, Command offCommand) {
this.onCommand = onCommand;
this.offCommand = offCommand;
this.undoCommand = null;
}
public void setUndoCommand(Command undoCommand) {
this.undoCommand = undoCommand;
}
public void pressOnButton() {
onCommand.execute();
setUndoCommand(onCommand);
}
public void pressOffButton() {
offCommand.execute();
setUndoCommand(offCommand);
}
public void pressUndoButton() {
if (undoCommand != null) {
undoCommand.undo();
}
}
}
主体程序
public class Client {
public static void main(String[] args) {
Light light = new Light();
Command onCommand = new LightOnCommand(light);
Command offCommand = new LightOffCommand(light);
RemoteControl remoteControl = new RemoteControl(onCommand, offCommand);
// 按下开灯按钮
remoteControl.pressOnButton();
// 按下关灯按钮
remoteControl.pressOffButton();
// 按下撤销按钮
remoteControl.pressUndoButton();
}
}
职责链模式
职责链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许你将请求沿着处理者链进行传递。每个处理者都可以处理请求或将其传递给下一个处理者。职责链模式的主要目的是将请求的发送者和接收者解耦,使得多个对象都有机会处理请求,从而增加系统的灵活性和可扩展性。
职责链模式通常涉及以下几个角色:
- 处理者接口(Handler):定义了处理请求的接口,以及设置下一个处理者的接口。
- 具体处理者(Concrete Handler):实现了处理者接口,负责处理请求或将其传递给下一个处理者。
- 客户端(Client):创建处理者链,并向链上的第一个处理者发送请求。
职责链模式的优点
- 解耦:职责链模式将请求的发送者和接收者解耦,使得两者可以独立变化。
- 灵活性:可以轻松地添加或删除处理者,而不需要修改现有代码。
- 动态配置:可以在运行时动态配置处理者链,提供了更高的灵活性。
- 责任分散:每个处理者只负责自己能够处理的部分,责任分散,易于维护。
职责链模式的缺点
- 复杂性增加:引入了多个处理者类,可能会增加系统的复杂性。
- 性能影响:如果处理者链过长,可能会导致性能下降,尤其是在请求需要经过多个处理者的情况下。
- 调试困难:由于请求可以在多个处理者之间传递,调试可能会变得困难。
处理者接口
public interface Handler {
void setNextHandler(Handler nextHandler);
void handleRequest(Request request);
}
具体处理者
public class ManagerHandler implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handleRequest(Request request) {
if (request.getAmount() <= 1000) {
System.out.println("Manager approved the request for " + request.getAmount() + " dollars.");
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
public class DirectorHandler implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handleRequest(Request request) {
if (request.getAmount() > 1000 && request.getAmount() <= 5000) {
System.out.println("Director approved the request for " + request.getAmount() + " dollars.");
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
public class CEOHandler implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handleRequest(Request request) {
if (request.getAmount() > 5000) {
System.out.println("CEO approved the request for " + request.getAmount() + " dollars.");
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
请求类
public class Request {
private double amount;
public Request(double amount) {
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
主体程序
ublic class Client {
public static void main(String[] args) {
// 创建处理者
Handler manager = new ManagerHandler();
Handler director = new DirectorHandler();
Handler ceo = new CEOHandler();
// 设置处理者链
manager.setNextHandler(director);
director.setNextHandler(ceo);
// 创建请求
Request request1 = new Request(800);
Request request2 = new Request(3000);
Request request3 = new Request(7000);
// 发送请求
manager.handleRequest(request1);
manager.handleRequest(request2);
manager.handleRequest(request3);
}
}
中介模式
中介模式(Mediator Pattern)是一种行为设计模式,它通过一个中介对象来封装一系列对象之间的交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介模式的主要目的是降低对象之间的耦合度,使得系统更加灵活和可扩展。
中介模式通常涉及以下几个角色:
- 中介者(Mediator):定义了同事对象(Colleague)注册和通信的接口。
- 具体中介者(Concrete Mediator):实现了中介者接口,协调各个同事对象之间的交互。
- 同事对象(Colleague):实现了同事接口,每个同事对象都知道中介者对象,并通过中介者与其他同事对象通信。
中介模式的优点
- 降低耦合度:中介模式通过中介者对象来协调各个同事对象之间的交互,降低了对象之间的耦合度。
- 集中控制:中介者对象集中管理对象之间的交互,使得系统的结构更加清晰和模块化。
- 灵活性:可以轻松地添加或删除同事对象,而不需要修改现有代码。
- 易扩展:中介者对象可以很容易地扩展新的功能,而不会影响现有的同事对象。
中介模式的缺点
- 中介者对象复杂:随着系统中同事对象的增加,中介者对象可能会变得非常复杂,难以维护。
- 性能影响:中介者对象需要管理所有的同事对象,可能会导致性能下降,特别是在对象数量较多的情况下。
中介接口
public interface ChatRoom {
void register(User user);
void sendMessage(String message, User user);
}
具体中介
import java.util.ArrayList;
import java.util.List;
public class ChatRoomImpl implements ChatRoom {
private List<User> users = new ArrayList<>();
@Override
public void register(User user) {
if (!users.contains(user)) {
users.add(user);
}
}
@Override
public void sendMessage(String message, User user) {
for (User u : users) {
if (u != user) {
u.receive(message);
}
}
}
}
同事接口
public interface User {
void send(String message);
void receive(String message);
}
具体同事
public class UserImpl implements User {
private String name;
private ChatRoom chatRoom;
public UserImpl(String name, ChatRoom chatRoom) {
this.name = name;
this.chatRoom = chatRoom;
chatRoom.register(this);
}
@Override
public void send(String message) {
chatRoom.sendMessage(message, this);
}
@Override
public void receive(String message) {
System.out.println(name + " received message: " + message);
}
}
主体程序
public class Client {
public static void main(String[] args) {
// 创建聊天室
ChatRoom chatRoom = new ChatRoomImpl();
// 创建用户
User user1 = new UserImpl("Alice", chatRoom);
User user2 = new UserImpl("Bob", chatRoom);
User user3 = new UserImpl("Charlie", chatRoom);
// 用户发送消息
user1.send("Hello, everyone!");
user2.send("Hi Alice!");
user3.send("Hey there!");
}
}
享元模式
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享已经存在的对象来减少创建对象的数量,从而降低系统的内存使用和提高性能。享元模式的主要目的是通过共享尽可能多的信息来减少内存占用,特别是在对象数量非常多且大部分对象是相同的场景下。
享元模式通常涉及以下几个角色:
- 享元接口(Flyweight):定义了外部状态和内部状态的接口方法。
- 具体享元(Concrete Flyweight):实现了享元接口,维护内部状态,并根据外部状态来提供具体的功能。
- 非享元(Unshared Concrete Flyweight):实现了享元接口,但不能共享,每次请求都会创建新的对象。
- 享元工厂(Flyweight Factory):管理享元对象的创建和共享,确保同一个内部状态的对象只创建一次。
享元接口
public interface Character {
void display(char externalState);
}
具体享元
public class CharacterImpl implements Character {
private char internalState;
public CharacterImpl(char internalState) {
this.internalState = internalState;
}
@Override
public void display(char externalState) {
System.out.println("Character: " + internalState + " with font size: " + externalState);
}
}
享元工厂
import java.util.HashMap;
import java.util.Map;
public class CharacterFactory {
private Map<Character, CharacterImpl> characters = new HashMap<>();
public Character getCharacter(char internalState) {
if (!characters.containsKey(internalState)) {
CharacterImpl character = new CharacterImpl(internalState);
characters.put(internalState, character);
}
return characters.get(internalState);
}
}
主体程序
public class Client {
public static void main(String[] args) {
// 创建享元工厂
CharacterFactory factory = new CharacterFactory();
// 获取享元对象
Character a = factory.getCharacter('A');
Character b = factory.getCharacter('B');
Character a2 = factory.getCharacter('A');
// 显示字符
a.display('12');
b.display('14');
a2.display('16');
}
}
解释器模式
解释器模式(Interpreter Pattern)是一种行为设计模式,它用于处理语言的语法或表达式。解释器模式定义了一个表达式的文法,然后用解释器来解析这些表达式。这种模式通常用于实现简单的语言解析和解释功能,例如查询语言、数学表达式等。
解释器模式通常涉及以下几个角色:
- 抽象表达式(Abstract Expression):定义了所有具体表达式都需要实现的解释方法。
- 终端表达式(Terminal Expression):表示文法中的终端符号,通常是最简单的表达式,不再包含其他表达式。
- 非终端表达式(Nonterminal Expression):表示文法中的非终端符号,通常包含一个或多个其他表达式。
- 上下文(Context):包含了解释器所需的全局信息,可以是变量值、环境信息等。
- 客户端(Client):构建文法树,并调用解释方法来解析表达式。
解释器模式的优点
- 扩展性:可以很容易地扩展新的表达式类型,只需要添加新的非终端表达式类。
- 灵活性:可以通过组合不同的表达式来构建复杂的表达式树,灵活性高。
- 清晰的结构:表达式的解析和解释过程结构清晰,易于理解和维护。
解释器模式的缺点
- 性能影响:对于复杂的表达式,解释器模式可能会导致性能下降,因为需要递归解析表达式树。
- 复杂性增加:引入了多个类和接口,可能会增加系统的复杂性。
- 不适合复杂的文法:对于非常复杂的文法,解释器模式可能会变得非常复杂和难以维护。
抽象表达式
public interface Expression {
int interpret(Context context);
}
上下文
public class Context {
private int result;
public void setResult(int result) {
this.result = result;
}
public int getResult() {
return result;
}
}
终端表达式
public class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret(Context context) {
return number;
}
}
非终端表达式
public class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
public class SubtractExpression implements Expression {
private Expression left;
private Expression right;
public SubtractExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) - right.interpret(context);
}
}
主体程序
public class Client {
public static void main(String[] args) {
// 构建表达式树
Expression expression = new AddExpression(
new NumberExpression(10),
new SubtractExpression(
new NumberExpression(20),
new NumberExpression(5)
)
);
// 创建上下文
Context context = new Context();
// 解释表达式
int result = expression.interpret(context);
System.out.println("Result: " + result); // 输出结果应为 25
}
}
访问者模式
访问者模式(Visitor Pattern)是一种行为设计模式,它允许你在不修改现有类的情况下向类添加新的操作。访问者模式的主要目的是将数据结构和操作数据的行为分离,使得可以动态地添加新的操作,而不需要修改现有的数据结构。
访问者模式通常涉及以下几个角色:
- 访问者接口(Visitor):定义了访问不同类型元素的方法。
- 具体访问者(Concrete Visitor):实现了访问者接口,定义了对每个元素的具体操作。
- 元素接口(Element):定义了接受访问者的方法。
- 具体元素(Concrete Element):实现了元素接口,提供了接受访问者的方法,并调用访问者的方法。
- 对象结构(Object Structure):包含元素对象的集合,可以遍历这些元素并接受访问者的访问。
访问者模式的优点
- 扩展性:可以在不修改现有类的情况下添加新的操作,只需要添加新的访问者类。
- 分离数据和操作:将数据结构和操作数据的行为分离,使得系统更加模块化和灵活。
- 单一职责原则:每个类只负责自己的职责,符合单一职责原则。
访问者模式的缺点
- 增加类的数量:引入了访问者接口和多个具体访问者类,可能会增加系统的类数量。
- 修改元素接口:如果需要添加新的元素类型,必须修改元素接口和所有具体元素类。
- 复杂性增加:增加了系统的复杂性,特别是对于复杂的对象结构。
访问者接口
public interface Visitor {
void visit(Paragraph paragraph);
void visit(Image image);
}
具体访问者
public class PrintVisitor implements Visitor {
@Override
public void visit(Paragraph paragraph) {
System.out.println("Printing paragraph: " + paragraph.getText());
}
@Override
public void visit(Image image) {
System.out.println("Printing image: " + image.getFileName());
}
}
public class SearchVisitor implements Visitor {
private String keyword;
public SearchVisitor(String keyword) {
this.keyword = keyword;
}
@Override
public void visit(Paragraph paragraph) {
if (paragraph.getText().contains(keyword)) {
System.out.println("Found keyword in paragraph: " + paragraph.getText());
}
}
@Override
public void visit(Image image) {
if (image.getFileName().contains(keyword)) {
System.out.println("Found keyword in image: " + image.getFileName());
}
}
}
元素接口
public interface Element {
void accept(Visitor visitor);
}
具体元素
public class Paragraph implements Element {
private String text;
public Paragraph(String text) {
this.text = text;
}
public String getText() {
return text;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Image implements Element {
private String fileName;
public Image(String fileName) {
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
对象结构
import java.util.ArrayList;
import java.util.List;
public class Document {
private List<Element> elements = new ArrayList<>();
public void addElement(Element element) {
elements.add(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
主体程序
public class Client {
public static void main(String[] args) {
// 创建文档
Document document = new Document();
document.addElement(new Paragraph("This is a paragraph."));
document.addElement(new Image("image1.jpg"));
document.addElement(new Paragraph("Another paragraph."));
// 打印文档
Visitor printVisitor = new PrintVisitor();
document.accept(printVisitor);
// 搜索文档
Visitor searchVisitor = new SearchVisitor("image");
document.accept(searchVisitor);
}
}