您现在的位置是:首页 >技术杂谈 >设计模式 (五) 设计模式实战系列网站首页技术杂谈
设计模式 (五) 设计模式实战系列
目录
设计模式实战系列是一系列实际应用设计模式的案例,旨在帮助读者更好地理解和应用设计模式。以下是设计模式实战系列的一些案例,它们涉及到不同的设计模式和应用场景,可以帮助读者更好地理解和应用设计模式。
一、创建型模式
1.单例模式实战
在这个案例中,我们将使用单例模式创建一个全局唯一的配置管理器,以便在整个应用程序中共享配置信息。具体实现如下:
// 配置管理器类
public class ConfigurationManager {
private static ConfigurationManager instance = new ConfigurationManager();
private Map<String, String> config = new HashMap<>();
private ConfigurationManager() {
// 加载配置信息
config.put("db.url", "jdbc:mysql://localhost:3306/test");
config.put("db.username", "root");
config.put("db.password", "123456");
}
public static ConfigurationManager getInstance() {
return instance;
}
public String getConfig(String key) {
return config.get(key);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ConfigurationManager configManager = ConfigurationManager.getInstance();
String dbUrl = configManager.getConfig("db.url");
String dbUsername = configManager.getConfig("db.username");
String dbPassword = configManager.getConfig("db.password");
System.out.println("db.url: " + dbUrl);
System.out.println("db.username: " + dbUsername);
System.out.println("db.password: " + dbPassword);
}
}
在这个例子中,我们定义了一个配置管理器类 ConfigurationManager,它使用私有构造函数和静态成员变量来实现单例模式。在构造函数中,我们加载了一些配置信息,并将它们存储在一个 Map 中。然后,我们定义了一个 getInstance 方法,用于获取全局唯一的配置管理器实例。最后,我们编写了一个客户端代码,使用配置管理器获取数据库连接信息,并输出到控制台上。
2.建造者模式实战
在这个案例中,我们将使用建造者模式创建一个复杂的电子商务网站,包括商品展示、购物车、结算等功能。具体实现如下:
// 商品类
public class Product {
private String name;
private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
// 购物车类
public class ShoppingCart {
private List<Product> products = new ArrayList<>();
public void addProduct(Product product) {
products.add(product);
}
public double getTotalPrice() {
double totalPrice = 0;
for (Product product : products) {
totalPrice += product.getPrice();
}
return totalPrice;
}
}
// 订单类
public class Order {
private String customerName;
private String shippingAddress;
private ShoppingCart shoppingCart;
public Order(String customerName, String shippingAddress, ShoppingCart shoppingCart) {
this.customerName = customerName;
this.shippingAddress = shippingAddress;
this.shoppingCart = shoppingCart;
}
public String getCustomerName() {
return customerName;
}
public String getShippingAddress() {
return shippingAddress;
}
public double getTotalPrice() {
return shoppingCart.getTotalPrice();
}
}
// 订单建造者接口
public interface OrderBuilder {
void buildCustomerName(String customerName);
void buildShippingAddress(String shippingAddress);
void buildShoppingCart(ShoppingCart shoppingCart);
Order getOrder();
}
// 订单建造者实现类
public class OnlineOrderBuilder implements OrderBuilder {
private Order order = new Order("", "", new ShoppingCart());
@Override
public void buildCustomerName(String customerName) {
order = new Order(customerName, order.getShippingAddress(), order.getShoppingCart());
}
@Override
public void buildShippingAddress(String shippingAddress) {
order = new Order(order.getCustomerName(), shippingAddress, order.getShoppingCart());
}
@Override
public void buildShoppingCart(ShoppingCart shoppingCart) {
order = new Order(order.getCustomerName(), order.getShippingAddress(), shoppingCart);
}
@Override
public Order getOrder() {
return order;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
OrderBuilder builder = new OnlineOrderBuilder();
builder.buildCustomerName("Alice");
builder.buildShippingAddress("123 Main St.");
ShoppingCart shoppingCart = new ShoppingCart();
shoppingCart.addProduct(new Product("iPhone", 999.99));
shoppingCart.addProduct(new Product("iPad", 799.99));
builder.buildShoppingCart(shoppingCart);
Order order = builder.getOrder();
System.out.println("Customer Name: " + order.getCustomerName());
System.out.println("Shipping Address: " + order.getShippingAddress());
System.out.println("Total Price: " + order.getTotalPrice());
}
}
在这个例子中,我们定义了一个商品类 Product、一个购物车类 ShoppingCart 和一个订单类 Order。然后,我们定义了一个订单建造者接口 OrderBuilder 和一个具体订单建造者实现类 OnlineOrderBuilder,用于创建订单对象。在客户端代码中,我们使用订单建造者创建一个订单对象,并输出订单的客户名称、配送地址和总价到控制台上。
3.原型模式实战
在这个案例中,我们将使用原型模式创建一个简单的图形编辑器,可以复制和粘贴图形对象。具体实现如下:
// 图形接口
public interface Shape extends Cloneable {
void draw();
Shape clone();
}
// 圆形类
public class Circle implements Shape {
private int x;
private int y;
private int radius;
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Drawing a circle at (" + x + ", " + y + ") with radius " + radius);
}
@Override
public Shape clone() {
return new Circle(x, y, radius);
}
}
// 矩形类
public class Rectangle implements Shape {
private int x;
private int y;
private int width;
private int height;
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("Drawing a rectangle at (" + x + ", " + y + ") with width " + width + " and height " + height);
}
@Override
public Shape clone() {
return new Rectangle(x, y, width, height);
}
}
// 图形编辑器类
public class GraphicsEditor {
private List<Shape> shapes = new ArrayList<>();
public void addShape(Shape shape) {
shapes.add(shape);
}
public void copyShape(int index) {
Shape shape = shapes.get(index).clone();
shapes.add(shape);
}
public void pasteShape(int index) {
Shape shape = shapes.get(shapes.size() - 1).clone();
shapes.add(index, shape);
}
public void drawShapes() {
for (Shape shape : shapes) {
shape.draw();
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
GraphicsEditor editor = new GraphicsEditor();
Circle circle = new Circle(100, 100, 50);
editor.addShape(circle);
Rectangle rectangle = new Rectangle(200, 200, 100, 50);
editor.addShape(rectangle);
editor.copyShape(0);
editor.pasteShape(2);
editor.drawShapes();
}
}
在这个例子中,我们定义了一个图形接口 Shape 和两个具体图形类 Circle 和 Rectangle。然后,我们定义了一个图形编辑器类 GraphicsEditor,它可以添加、复制、粘贴和绘制图形对象。在客户端代码中,我们使用图形编辑器创建两个图形对象,并复制和粘贴第一个图形对象,最后绘制所有图形对象。
4.工厂方法模式实战
在实践中,工厂方法模式常用于创建对象的场景,例如在一个电商网站中,需要创建不同类型的商品对象,可以使用工厂方法模式来实现。
具体实现如下:
// 商品接口
public interface Product {
void showInfo();
}
// 电视类
public class TV implements Product {
@Override
public void showInfo() {
System.out.println("This is a TV");
}
}
// 手机类
public class Phone implements Product {
@Override
public void showInfo() {
System.out.println("This is a phone");
}
}
// 商品工厂接口
public interface ProductFactory {
Product createProduct();
}
// 电视工厂类
public class TVFactory implements ProductFactory {
@Override
public Product createProduct() {
return new TV();
}
}
// 手机工厂类
public class PhoneFactory implements ProductFactory {
@Override
public Product createProduct() {
return new Phone();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ProductFactory tvFactory = new TVFactory();
Product tv = tvFactory.createProduct();
tv.showInfo();
ProductFactory phoneFactory = new PhoneFactory();
Product phone = phoneFactory.createProduct();
phone.showInfo();
}
}
在这个例子中,我们定义了一个商品接口 Product 和两个具体商品类 TV 和 Phone,它们分别实现了商品的展示方法。然后,我们定义了一个商品工厂接口 ProductFactory 和两个具体商品工厂类 TVFactory 和 PhoneFactory,它们分别实现了创建商品的方法。在客户端代码中,我们创建了一个电视工厂对象和一个手机工厂对象,并分别使用它们来创建电视和手机对象,最后调用它们的展示方法。由于工厂方法模式是将对象的创建延迟到子类中,从而使得客户端代码不需要直接依赖具体的产品类,所以我们可以通过它来实现程序的灵活性和可扩展性。
5.抽象工厂模式实战
在实际应用中,抽象工厂模式可以用于创建一系列相关的对象,例如在一个游戏中,需要创建不同类型的角色和装备对象,可以使用抽象工厂模式来实现。
具体实现如下:
// 角色接口
public interface Role {
void showInfo();
}
// 战士类
public class Warrior implements Role {
@Override
public void showInfo() {
System.out.println("This is a warrior");
}
}
// 法师类
public class Mage implements Role {
@Override
public void showInfo() {
System.out.println("This is a mage");
}
}
// 装备接口
public interface Equipment {
void showInfo();
}
// 武器类
public class Weapon implements Equipment {
@Override
public void showInfo() {
System.out.println("This is a weapon");
}
}
// 盾牌类
public class Shield implements Equipment {
@Override
public void showInfo() {
System.out.println("This is a shield");
}
}
// 抽象工厂接口
public interface AbstractFactory {
Role createRole();
Equipment createEquipment();
}
// 战士工厂类
public class WarriorFactory implements AbstractFactory {
@Override
public Role createRole() {
return new Warrior();
}
@Override
public Equipment createEquipment() {
return new Weapon();
}
}
// 法师工厂类
public class MageFactory implements AbstractFactory {
@Override
public Role createRole() {
return new Mage();
}
@Override
public Equipment createEquipment() {
return new Shield();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
AbstractFactory warriorFactory = new WarriorFactory();
Role warrior = warriorFactory.createRole();
Equipment weapon = warriorFactory.createEquipment();
warrior.showInfo();
weapon.showInfo();
AbstractFactory mageFactory = new MageFactory();
Role mage = mageFactory.createRole();
Equipment shield = mageFactory.createEquipment();
mage.showInfo();
shield.showInfo();
}
}
在这个例子中,我们定义了一个角色接口 Role 和两个具体角色类 Warrior 和 Mage,它们分别实现了角色的展示方法。同时,我们定义了一个装备接口 Equipment 和两个具体装备类 Weapon 和 Shield,它们分别实现了装备的展示方法。然后,我们定义了一个抽象工厂接口 AbstractFactory 和两个具体工厂类 WarriorFactory 和 MageFactory,它们分别实现了创建角色和装备的方法。在客户端代码中,我们创建了一个战士工厂对象和一个法师工厂对象,并分别使用它们来创建战士和法师对象以及对应的装备对象,最后调用它们的展示方法。由于抽象工厂模式是将对象的创建延迟到子类中,从而使得客户端代码不需要直接依赖具体的产品类,所以我们可以通过它来实现程序的灵活性和可扩展性。
二、结构型模式
6.适配器模式实战
在这个案例中,我们将使用适配器模式将一个老的音频播放器适配成一个新的多媒体播放器,以便支持不同的音频格式。具体实现如下:
// 老的音频播放器接口
public interface AudioPlayer {
void playMp3(String fileName);
void playWav(String fileName);
}
// 老的音频播放器实现类
public class LegacyAudioPlayer implements AudioPlayer {
@Override
public void playMp3(String fileName) {
System.out.println("Playing MP3 file: " + fileName);
}
@Override
public void playWav(String fileName) {
System.out.println("Playing WAV file: " + fileName);
}
}
// 新的多媒体播放器接口
public interface MediaPlayer {
void play(String fileName);
}
// 新的多媒体播放器实现类
public class MultimediaPlayer implements MediaPlayer {
@Override
public void play(String fileName) {
if (fileName.endsWith(".mp3")) {
AudioPlayer audioPlayer = new LegacyAudioPlayer();
audioPlayer.playMp3(fileName);
} else if (fileName.endsWith(".wav")) {
AudioPlayer audioPlayer = new LegacyAudioPlayer();
audioPlayer.playWav(fileName);
} else {
throw new IllegalArgumentException("Unsupported media type: " + fileName);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
MediaPlayer mediaPlayer = new MultimediaPlayer();
mediaPlayer.play("song.mp3");
mediaPlayer.play("sound.wav");
mediaPlayer.play("movie.mp4");
}
}
在这个例子中,我们定义了一个老的音频播放器接口 AudioPlayer 和一个具体实现类 LegacyAudioPlayer,它可以播放 MP3 和 WAV 格式的音频文件。然后,我们定义了一个新的多媒体播放器接口 MediaPlayer 和一个具体实现类 MultimediaPlayer,它可以适配老的音频播放器,以便支持不同的音频格式。在客户端代码中,我们使用新的多媒体播放器播放 MP3、WAV 和不支持的文件,最后输出一个异常信息。
7.桥接模式实战
在这个案例中,我们将使用桥接模式将一个抽象的图形类和一个具体的颜色类分离,以便支持不同的图形和颜色组合。具体实现如下:
// 颜色接口
public interface Color {
void applyColor();
}
// 红色实现类
public class Red implements Color {
@Override
public void applyColor() {
System.out.println("Applying red color");
}
}
// 绿色实现类
public class Green implements Color {
@Override
public void applyColor() {
System.out.println("Applying green color");
}
}
// 图形抽象类
public abstract class Shape {
protected Color color;
public Shape(Color color) {
this.color = color;
}
public abstract void draw();
}
// 圆形实现类
public class Circle extends Shape {
private int x;
private int y;
private int radius;
public Circle(int x, int y, int radius, Color color) {
super(color);
this.x = x;
this.y = y;
this.radius = radius;
}
@Override
public void draw() {
System.out.print("Drawing a circle at (" + x + ", " + y + ") with radius " + radius + " ");
color.applyColor();
}
}
// 矩形实现类
public class Rectangle extends Shape {
private int x;
private int y;
private int width;
private int height;
public Rectangle(int x, int y, int width, int height, Color color) {
super(color);
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.print("Drawing a rectangle at (" + x + ", " + y + ") with width " + width + " and height " + height + " ");
color.applyColor();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Shape circle = new Circle(100, 100, 50, new Red());
Shape rectangle = new Rectangle(200, 200, 100, 50, new Green());
circle.draw();
rectangle.draw();
}
}
在这个例子中,我们定义了一个颜色接口 Color 和两个具体颜色实现类 Red 和 Green。然后,我们定义了一个图形抽象类 Shape,它包含一个颜色成员变量和一个抽象的 draw 方法。最后,我们定义了两个具体图形实现类 Circle 和 Rectangle,它们继承自 Shape 类,并实现了 draw 方法。在客户端代码中,我们创建了一个红色的圆形和一个绿色的矩形,并分别调用它们的 draw 方法。
8.装饰器模式实战
在这个案例中,我们将使用装饰器模式来扩展一个简单的咖啡店,以支持添加不同的配料。具体实现如下:
// 咖啡接口
public interface Coffee {
double getCost();
String getDescription();
}
// 咖啡实现类
public class SimpleCoffee implements Coffee {
@Override
public double getCost() {
return 1.0;
}
@Override
public String getDescription() {
return "Simple coffee";
}
}
// 配料装饰器抽象类
public abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee;
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double getCost() {
return coffee.getCost();
}
@Override
public String getDescription() {
return coffee.getDescription();
}
}
// 牛奶装饰器实现类
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double getCost() {
return super.getCost() + 0.5;
}
@Override
public String getDescription() {
return super.getDescription() + ", with milk";
}
}
// 糖浆装饰器实现类
public class SyrupDecorator extends CoffeeDecorator {
public SyrupDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double getCost() {
return super.getCost() + 0.3;
}
@Override
public String getDescription() {
return super.getDescription() + ", with syrup";
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SyrupDecorator(coffee);
System.out.println("Cost: " + coffee.getCost());
System.out.println("Description: " + coffee.getDescription());
}
}
在这个例子中,我们定义了一个咖啡接口 Coffee 和一个具体实现类 SimpleCoffee,它表示一杯简单的咖啡。然后,我们定义了一个装饰器抽象类 CoffeeDecorator,它包含一个咖啡成员变量,并实现了咖啡接口的方法。最后,我们定义了两个具体装饰器实现类 MilkDecorator 和 SyrupDecorator,它们分别表示加牛奶和加糖浆的咖啡。在客户端代码中,我们创建了一杯简单的咖啡,并使用装饰器分别加上牛奶和糖浆,最后输出咖啡的价格和描述。
9.组合模式实战
在这个案例中,我们将使用组合模式创建一个简单的组织结构图,包括部门和员工两种节点类型。具体实现如下:
// 组织结构图节点接口
public interface Node {
String getName();
void print();
}
// 部门节点实现类
public class Department implements Node {
private String name;
private List<Node> children = new ArrayList<>();
public Department(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
public void add(Node node) {
children.add(node);
}
public void remove(Node node) {
children.remove(node);
}
@Override
public void print() {
System.out.println("Department: " + name);
for (Node node : children) {
node.print();
}
}
}
// 员工节点实现类
public class Employee implements Node {
private String name;
public Employee(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void print() {
System.out.println("Employee: " + name);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Department engineering = new Department("Engineering");
Department sales = new Department("Sales");
Employee alice = new Employee("Alice");
Employee bob = new Employee("Bob");
Employee charlie = new Employee("Charlie");
Employee dave = new Employee("Dave");
engineering.add(alice);
engineering.add(bob);
sales.add(charlie);
sales.add(dave);
Department company = new Department("Company");
company.add(engineering);
company.add(sales);
company.print();
}
}
在这个例子中,我们定义了一个组织结构图节点接口 Node 和两个具体实现类 Department 和 Employee,分别表示部门和员工节点。部门节点包含一个名称和一个子节点列表,可以添加、删除和打印子节点。员工节点只包含一个名称,可以打印自己。在客户端代码中,我们创建了一个公司节点,并添加了两个部门节点和四个员工节点,最后打印整个组织结构图。
10.外观模式实战
在这个案例中,我们将使用外观模式创建一个简单的家庭影院系统,包括投影仪、音响和 DVD 播放器三个子系统。具体实现如下:
// 投影仪子系统
public class Projector {
public void on() {
System.out.println("Projector is on");
}
public void off() {
System.out.println("Projector is off");
}
public void setInput(String input) {
System.out.println("Setting input to " + input);
}
}
// 音响子系统
public class Amplifier {
public void on() {
System.out.println("Amplifier is on");
}
public void off() {
System.out.println("Amplifier is off");
}
public void setVolume(int volume) {
System.out.println("Setting volume to " + volume);
}
}
// DVD 播放器子系统
public class DvdPlayer {
public void on() {
System.out.println("DVD player is on");
}
public void off() {
System.out.println("DVD player is off");
}
public void play(String movie) {
System.out.println("Playing movie " + movie);
}
}
// 家庭影院外观类
public class HomeTheaterFacade {
private Projector projector;
private Amplifier amplifier;
private DvdPlayer dvdPlayer;
public HomeTheaterFacade(Projector projector, Amplifier amplifier, DvdPlayer dvdPlayer) {
this.projector = projector;
this.amplifier = amplifier;
this.dvdPlayer = dvdPlayer;
}
public void watchMovie(String movie) {
System.out.println("Get ready to watch a movie...");
projector.on();
amplifier.on();
dvdPlayer.on();
dvdPlayer.play(movie);
}
public void endMovie() {
System.out.println("Shutting down the movie theater...");
projector.off();
amplifier.off();
dvdPlayer.off();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Projector projector = new Projector();
Amplifier amplifier = new Amplifier();
DvdPlayer dvdPlayer = new DvdPlayer();
HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade(projector, amplifier, dvdPlayer);
homeTheaterFacade.watchMovie("The Shawshank Redemption");
homeTheaterFacade.endMovie();
}
}
在这个例子中,我们定义了三个子系统类 Projector、Amplifier 和 DvdPlayer,分别表示投影仪、音响和 DVD 播放器。然后,我们定义了一个家庭影院外观类 HomeTheaterFacade,它包含三个子系统成员变量,并提供了两个方法 watchMovie 和 endMovie,分别表示开始和结束观看电影。在客户端代码中,我们创建了三个子系统对象和一个家庭影院外观对象,并使用外观对象观看了一部电影,最后结束观影。
11.享元模式实战
在这个案例中,我们将使用享元模式创建一个简单的棋盘游戏,包括黑白两种棋子和一个棋盘。具体实现如下:
// 棋子接口
public interface ChessPiece {
void setColor(String color);
String getColor();
void setPosition(int x, int y);
int[] getPosition();
void move(int x, int y);
}
// 棋子实现类
public class ChessPieceImpl implements ChessPiece {
private String color;
private int x;
private int y;
public ChessPieceImpl(String color) {
this.color = color;
}
@Override
public void setColor(String color) {
this.color = color;
}
@Override
public String getColor() {
return color;
}
@Override
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public int[] getPosition() {
return new int[] {x, y};
}
@Override
public void move(int x, int y) {
System.out.println("Moving " + color + " chess piece to (" + x + ", " + y + ")");
setPosition(x, y);
}
}
// 棋盘类
public class ChessBoard {
private Map<String, ChessPiece> pieces = new HashMap<>();
public ChessBoard() {
pieces.put("black", new ChessPieceImpl("black"));
pieces.put("white", new ChessPieceImpl("white"));
}
public void move(String color, int x, int y) {
pieces.get(color).move(x, y);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ChessBoard chessBoard = new ChessBoard();
chessBoard.move("black", 1, 1);
chessBoard.move("white", 2, 2);
chessBoard.move("black", 3, 3);
chessBoard.move("white", 4, 4);
}
}
在这个例子中,我们定义了一个棋子接口 ChessPiece 和一个具体实现类 ChessPieceImpl,它包含颜色、位置和移动方法。然后,我们定义了一个棋盘类 ChessBoard,它包含一个棋子映射 pieces,并提供了一个移动棋子的方法 move。在客户端代码中,我们创建了一个棋盘对象,并使用它移动了四个棋子。由于棋子是享元模式的应用,所以我们只需要创建两个棋子对象,即可在棋盘上任意移动。
12.代理模式实战
在这个案例中,我们将使用代理模式创建一个简单的图片浏览器,包括图片和代理两种对象。具体实现如下:
// 图片接口
public interface Image {
void display();
}
// 真实图片类
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk();
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk() {
System.out.println("Loading " + fileName + " from disk");
}
}
// 图片代理类
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();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Image image = new ImageProxy("test.jpg");
image.display();
}
}
在这个例子中,我们定义了一个图片接口 Image 和一个真实图片类 RealImage,它包含了图片的文件名和加载图片的方法,并实现了显示图片的方法。然后,我们定义了一个图片代理类 ImageProxy,它包含了图片的文件名和真实图片对象 realImage,并实现了显示图片的方法。在客户端代码中,我们创建了一个图片代理对象,并调用了它的显示方法。由于图片代理是代理模式的应用,所以我们可以通过它来控制真实图片的访问,并在需要时才加载真实图片,从而提高程序的性能。
三、行为型模式
13.模板方法模式实战
在实际应用中,模板方法模式可以用于定义一系列算法的骨架,让子类实现具体的算法细节,例如在一个游戏中,需要实现不同类型的角色升级算法,可以使用模板方法模式来实现。
具体实现如下:
// 角色抽象类
public abstract class Role {
// 定义升级算法的骨架
public final void levelUp() {
System.out.println("Current level: " + getLevel());
System.out.println("Experience: " + getExperience());
addExperience();
System.out.println("Experience after adding: " + getExperience());
if (isLevelUp()) {
levelUpMessage();
levelUpAction();
} else {
System.out.println("Not enough experience to level up");
}
}
// 获取角色等级
protected abstract int getLevel();
// 获取角色经验值
protected abstract int getExperience();
// 添加经验值
protected abstract void addExperience();
// 判断是否可以升级
protected abstract boolean isLevelUp();
// 显示升级信息
protected void levelUpMessage() {
System.out.println("Congratulations! Level up!");
}
// 升级后的动作
protected abstract void levelUpAction();
}
// 战士类
public class Warrior extends Role {
private int level = 1;
private int experience = 0;
@Override
protected int getLevel() {
return level;
}
@Override
protected int getExperience() {
return experience;
}
@Override
protected void addExperience() {
experience += 10;
}
@Override
protected boolean isLevelUp() {
return experience >= level * 100;
}
@Override
protected void levelUpAction() {
System.out.println("Warrior learned a new skill!");
}
}
// 法师类
public class Mage extends Role {
private int level = 1;
private int experience = 0;
@Override
protected int getLevel() {
return level;
}
@Override
protected int getExperience() {
return experience;
}
@Override
protected void addExperience() {
experience += 20;
}
@Override
protected boolean isLevelUp() {
return experience >= level * 200;
}
@Override
protected void levelUpAction() {
System.out.println("Mage learned a new spell!");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Role warrior = new Warrior();
warrior.levelUp();
Role mage = new Mage();
mage.levelUp();
}
}
在这个例子中,我们定义了一个角色抽象类 Role,它定义了升级算法的骨架,包括获取角色等级和经验值、添加经验值、判断是否可以升级、显示升级信息和升级后的动作。然后,我们定义了两个具体角色类 Warrior 和 Mage,它们分别实现了角色的具体算法细节。在客户端代码中,我们创建了一个战士对象和一个法师对象,并分别调用它们的升级方法,输出升级信息。由于模板方法模式是将算法的骨架定义在抽象类中,具体算法细节由子类实现,所以我们可以通过它来实现程序的灵活性和可扩展性。
14.命令模式实战
在实际应用中,命令模式可以用于将请求封装成对象,从而使得可以将请求的发送者和接收者解耦,例如在一个游戏中,需要实现不同类型的角色使用不同的技能,可以使用命令模式来实现。
具体实现如下:
// 技能接口
public interface Skill {
void use();
}
// 战士技能类
public class WarriorSkill implements Skill {
@Override
public void use() {
System.out.println("Warrior uses skill: Charge!");
}
}
// 法师技能类
public class MageSkill implements Skill {
@Override
public void use() {
System.out.println("Mage uses skill: Fireball!");
}
}
// 命令接口
public interface Command {
void execute();
}
// 使用技能命令类
public class UseSkillCommand implements Command {
private Skill skill;
public UseSkillCommand(Skill skill) {
this.skill = skill;
}
@Override
public void execute() {
skill.use();
}
}
// 角色类
public class Role {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void useSkill() {
command.execute();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Role warrior = new Role();
Skill warriorSkill = new WarriorSkill();
Command warriorCommand = new UseSkillCommand(warriorSkill);
warrior.setCommand(warriorCommand);
warrior.useSkill();
Role mage = new Role();
Skill mageSkill = new MageSkill();
Command mageCommand = new UseSkillCommand(mageSkill);
mage.setCommand(mageCommand);
mage.useSkill();
}
}
在这个例子中,我们定义了一个技能接口 Skill 和两个具体技能类 WarriorSkill 和 MageSkill,它们分别实现了使用技能的方法。然后,我们定义了一个命令接口 Command 和一个具体命令类 UseSkillCommand,它们分别定义了执行命令的方法。在角色类 Role 中,我们定义了一个命令对象,并提供了设置命令和使用技能的方法。在客户端代码中,我们创建了一个战士对象和一个法师对象,并分别创建了对应的技能对象和命令对象,最后将命令对象设置给角色对象,并调用使用技能的方法。由于命令模式是将请求封装成对象,从而使得可以将请求的发送者和接收者解耦,所以我们可以通过它来实现程序的灵活性和可扩展性。
15.访问者模式实战
在实际应用中,访问者模式可以用于对一组对象进行操作,而不需要修改这些对象的类定义,例如在一个游戏中,需要实现不同类型的角色进行不同的操作,可以使用访问者模式来实现。
具体实现如下:
// 角色接口
public interface Role {
void accept(Visitor visitor);
}
// 战士类
public class Warrior implements Role {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void attack() {
System.out.println("Warrior attacks!");
}
}
// 法师类
public class Mage implements Role {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void castSpell() {
System.out.println("Mage casts spell!");
}
}
// 访问者接口
public interface Visitor {
void visit(Warrior warrior);
void visit(Mage mage);
}
// 攻击访问者类
public class AttackVisitor implements Visitor {
@Override
public void visit(Warrior warrior) {
warrior.attack();
}
@Override
public void visit(Mage mage) {
System.out.println("Mage cannot attack!");
}
}
// 施法访问者类
public class CastSpellVisitor implements Visitor {
@Override
public void visit(Warrior warrior) {
System.out.println("Warrior cannot cast spell!");
}
@Override
public void visit(Mage mage) {
mage.castSpell();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Role warrior = new Warrior();
Role mage = new Mage();
Visitor attackVisitor = new AttackVisitor();
Visitor castSpellVisitor = new CastSpellVisitor();
warrior.accept(attackVisitor);
warrior.accept(castSpellVisitor);
mage.accept(attackVisitor);
mage.accept(castSpellVisitor);
}
}
在这个例子中,我们定义了一个角色接口 Role 和两个具体角色类 Warrior 和 Mage,它们分别实现了接受访问者的方法。同时,我们定义了一个访问者接口 Visitor 和两个具体访问者类 AttackVisitor 和 CastSpellVisitor,它们分别实现了对不同类型角色的不同操作。在客户端代码中,我们创建了一个战士对象和一个法师对象,并创建了对应的攻击访问者和施法访问者对象,最后将访问者对象传递给角色对象,调用接受访问者的方法。由于访问者模式是对一组对象进行操作,而不需要修改这些对象的类定义,所以我们可以通过它来实现程序的灵活性和可扩展性。
16.迭代器模式实战
在实际应用中,迭代器模式可以用于遍历一个集合对象,而不需要暴露其内部结构,例如在一个游戏中,需要实现遍历不同类型的角色,可以使用迭代器模式来实现。
具体实现如下:
// 角色类
public class Role {
private String name;
public Role(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 角色集合类
public class RoleCollection implements Iterable<Role> {
private List<Role> roles = new ArrayList<>();
public void addRole(Role role) {
roles.add(role);
}
public void removeRole(Role role) {
roles.remove(role);
}
@Override
public Iterator<Role> iterator() {
return new RoleIterator();
}
// 角色迭代器类
private class RoleIterator implements Iterator<Role> {
private int index = 0;
@Override
public boolean hasNext() {
return index < roles.size();
}
@Override
public Role next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Role role = roles.get(index);
index++;
return role;
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
RoleCollection roleCollection = new RoleCollection();
roleCollection.addRole(new Role("Warrior"));
roleCollection.addRole(new Role("Mage"));
for (Role role : roleCollection) {
System.out.println("Role: " + role.getName());
}
}
}
在这个例子中,我们定义了一个角色类 Role 和一个角色集合类 RoleCollection,它实现了 Iterable 接口,从而可以使用 foreach 循环遍历。在角色集合类中,我们定义了一个角色迭代器类 RoleIterator,它实现了 Iterator 接口,从而可以使用 hasNext 和 next 方法遍历角色集合。在客户端代码中,我们创建了一个角色集合对象,并添加了两个角色对象,最后使用 foreach 循环遍历角色集合,输出角色名字。由于迭代器模式可以遍历一个集合对象,而不需要暴露其内部结构,所以我们可以通过它来实现程序的灵活性和可扩展性。
17.观察者模式实战
观察者模式实战:
在实际应用中,观察者模式可以用于实现对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新,例如在一个游戏中,需要实现角色受到攻击时,其他角色也能收到通知,可以使用观察者模式来实现。
具体实现如下:
// 观察者接口
public interface Observer {
void update(String message);
}
// 观察者实现类
public class Player implements Observer {
private String name;
public Player(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}
// 被观察者接口
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers(String message);
}
// 被观察者实现类
public class Game implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
public void attack() {
System.out.println("Player is attacking!");
notifyObservers("Player is attacking!");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Game game = new Game();
Player player1 = new Player("Player 1");
Player player2 = new Player("Player 2");
Player player3 = new Player("Player 3");
game.attach(player1);
game.attach(player2);
game.attach(player3);
game.attack();
game.detach(player2);
game.attack();
}
}
在这个例子中,我们定义了一个观察者接口 Observer 和一个观察者实现类 Player,它实现了更新方法。同时,我们定义了一个被观察者接口 Subject 和一个被观察者实现类 Game,它实现了添加、删除和通知观察者的方法。在客户端代码中,我们创建了一个游戏对象和三个玩家对象,并将玩家对象注册为游戏对象的观察者,然后调用游戏对象的攻击方法,观察者们都会收到通知。最后,我们将一个玩家对象从观察者列表中删除,再次调用攻击方法,只有两个观察者会收到通知。由于观察者模式可以实现对象之间的一对多依赖关系,所以我们可以通过它来实现程序的灵活性和可扩展性。
18.中介者模式实战
在实际应用中,中介者模式可以用于减少对象之间的直接耦合,将对象之间的交互转移到中介者对象中,例如在一个游戏中,需要实现不同类型的角色之间的交互,可以使用中介者模式来实现。
具体实现如下:
// 中介者接口
public interface Mediator {
void send(String message, Role role);
}
// 具体中介者类
public class GameMediator implements Mediator {
private List<Role> roles = new ArrayList<>();
@Override
public void send(String message, Role role) {
for (Role r : roles) {
if (r != role) {
r.receive(message);
}
}
}
public void addRole(Role role) {
roles.add(role);
}
}
// 角色类
public abstract class Role {
protected Mediator mediator;
public Role(Mediator mediator) {
this.mediator = mediator;
}
public abstract void send(String message);
public abstract void receive(String message);
}
// 具体角色类
public class Warrior extends Role {
public Warrior(Mediator mediator) {
super(mediator);
}
@Override
public void send(String message) {
mediator.send(message, this);
}
@Override
public void receive(String message) {
System.out.println("Warrior received message: " + message);
}
}
public class Mage extends Role {
public Mage(Mediator mediator) {
super(mediator);
}
@Override
public void send(String message) {
mediator.send(message, this);
}
@Override
public void receive(String message) {
System.out.println("Mage received message: " + message);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
GameMediator mediator = new GameMediator();
Role warrior = new Warrior(mediator);
Role mage = new Mage(mediator);
mediator.addRole(warrior);
mediator.addRole(mage);
warrior.send("Attack!");
mage.send("Cast spell!");
}
}
在这个例子中,我们定义了一个中介者接口 Mediator 和一个具体中介者类 GameMediator,它实现了发送消息的方法,并维护了一个角色列表。同时,我们定义了一个角色类 Role 和两个具体角色类 Warrior 和 Mage,它们实现了发送和接收消息的方法。在客户端代码中,我们创建了一个中介者对象和两个角色对象,并将角色对象注册到中介者对象中,然后调用角色对象的发送消息方法,中介者对象会将消息发送给其他角色对象。由于中介者模式可以减少对象之间的直接耦合,所以我们可以通过它来实现程序的灵活性和可扩展性。
19.备忘录模式实战
在实际应用中,备忘录模式可以用于保存和恢复对象的状态,例如在一个游戏中,需要实现保存和恢复角色的状态,可以使用备忘录模式来实现。
具体实现如下:
// 备忘录类
public class Memento {
private int level;
public Memento(int level) {
this.level = level;
}
public int getLevel() {
return level;
}
}
// 角色类
public class Role {
private int level;
public Role(int level) {
this.level = level;
}
public void setLevel(int level) {
this.level = level;
}
public Memento save() {
return new Memento(level);
}
public void restore(Memento memento) {
level = memento.getLevel();
}
public void display() {
System.out.println("Level: " + level);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Role role = new Role(1);
role.display();
Memento memento = role.save();
role.setLevel(2);
role.display();
role.restore(memento);
role.display();
}
}
在这个例子中,我们定义了一个备忘录类 Memento 和一个角色类 Role,它实现了保存和恢复状态的方法。在客户端代码中,我们创建了一个角色对象,并调用 display 方法显示当前等级。然后,我们保存当前状态到备忘录对象中,将等级设置为 2,并再次调用 display 方法显示当前等级。最后,我们将备忘录对象传递给角色对象的恢复方法,将等级恢复到之前保存的状态,并再次调用 display 方法显示当前等级。由于备忘录模式可以保存和恢复对象的状态,所以我们可以通过它来实现程序的灵活性和可扩展性。
20.解释器模式实战
在实际应用中,解释器模式可以用于解析和执行一些特定的语法规则,例如在一个游戏中,需要实现解析和执行一些特定的指令,可以使用解释器模式来实现。
具体实现如下:
// 抽象表达式类
public interface Expression {
int interpret();
}
// 数字表达式类
public class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
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() {
return left.interpret() + right.interpret();
}
}
// 减法表达式类
public class SubExpression implements Expression {
private Expression left;
private Expression right;
public SubExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() - right.interpret();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Expression expression = new SubExpression(
new AddExpression(new NumberExpression(10), new NumberExpression(5)),
new NumberExpression(3)
);
System.out.println(expression.interpret());
}
}
在这个例子中,我们定义了一个抽象表达式类 Expression 和三个具体表达式类 NumberExpression、AddExpression 和 SubExpression,它们实现了解释和执行表达式的方法。在客户端代码中,我们创建了一个表达式对象,并使用加法和减法表达式组合成一个复杂的表达式,最后调用 interpret 方法执行表达式并输出结果。由于解释器模式可以解析和执行一些特定的语法规则,所以我们可以通过它来实现程序的灵活性和可扩展性。
21.策略模式实战
在实际应用中,策略模式可以用于实现不同的算法或行为,使得它们可以相互替换,例如在一个游戏中,需要实现不同类型的攻击方式,可以使用策略模式来实现。
具体实现如下:
// 攻击策略接口
public interface AttackStrategy {
void attack();
}
// 近战攻击策略类
public class MeleeAttackStrategy implements AttackStrategy {
@Override
public void attack() {
System.out.println("Melee attack!");
}
}
// 远程攻击策略类
public class RangedAttackStrategy implements AttackStrategy {
@Override
public void attack() {
System.out.println("Ranged attack!");
}
}
// 角色类
public class Role {
private AttackStrategy attackStrategy;
public void setAttackStrategy(AttackStrategy attackStrategy) {
this.attackStrategy = attackStrategy;
}
public void attack() {
attackStrategy.attack();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Role warrior = new Role();
warrior.setAttackStrategy(new MeleeAttackStrategy());
warrior.attack();
Role mage = new Role();
mage.setAttackStrategy(new RangedAttackStrategy());
mage.attack();
}
}
在这个例子中,我们定义了一个攻击策略接口 AttackStrategy 和两个具体攻击策略类 MeleeAttackStrategy 和 RangedAttackStrategy,它们实现了不同的攻击方式。同时,我们定义了一个角色类 Role,它包含一个攻击策略对象,并实现了攻击方法。在客户端代码中,我们创建了两个角色对象,并分别设置不同的攻击策略,最后调用攻击方法执行攻击。由于策略模式可以实现不同的算法或行为,使得它们可以相互替换,所以我们可以通过它来实现程序的灵活性和可扩展性。
命令模式实战:
在实际应用中,命令模式可以用于将请求封装成对象,使得可以将请求的发送者和接收者解耦,例如在一个游戏中,需要实现将不同类型的指令封装成对象,可以使用命令模式来实现。
具体实现如下:
```java
// 命令接口
public interface Command {
void execute();
}
// 具体命令类
public class AttackCommand implements Command {
private Role role;
public AttackCommand(Role role) {
this.role = role;
}
@Override
public void execute() {
role.attack();
}
}
// 角色类
public class Role {
public void attack() {
System.out.println("Attack!");
}
}
// 命令调用者类
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Role role = new Role();
Command command = new AttackCommand(role);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.executeCommand();
}
}
在这个例子中,我们定义了一个攻击策略接口 AttackStrategy 和两个具体攻击策略类 MeleeAttackStrategy 和 RangedAttackStrategy,它们实现了不同的攻击方式。同时,我们定义了一个角色类 Role,它包含一个攻击策略对象,并实现了攻击方法。在客户端代码中,我们创建了两个角色对象,并分别设置不同的攻击策略,最后调用攻击方法执行攻击。由于策略模式可以实现不同的算法或行为,使得它们可以相互替换,所以我们可以通过它来实现程序的灵活性和可扩展性。
22.命令模式实战
在实际应用中,命令模式可以用于将请求封装成对象,使得可以将请求的发送者和接收者解耦,例如在一个游戏中,需要实现将不同类型的指令封装成对象,可以使用命令模式来实现。
具体实现如下:
// 命令接口
public interface Command {
void execute();
}
// 具体命令类
public class AttackCommand implements Command {
private Role role;
public AttackCommand(Role role) {
this.role = role;
}
@Override
public void execute() {
role.attack();
}
}
// 角色类
public class Role {
public void attack() {
System.out.println("Attack!");
}
}
// 命令调用者类
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Role role = new Role();
Command command = new AttackCommand(role);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.executeCommand();
}
}
在这个例子中,我们定义了一个命令接口 Command 和一个具体命令类 AttackCommand,它实现了执行攻击的方法。同时,我们定义了一个角色类 Role,它包含了攻击方法。在命令调用者类 Invoker 中,我们设置了一个命令对象,并实现了执行命令的方法。在客户端代码中,我们创建了一个角色对象和一个命令对象,并将命令对象设置到命令调用者对象中,最后调用命令调用者对象的执行命令方法。由于命令模式可以将请求封装成对象,使得可以将请求的发送者和接收者解耦,所以我们可以通过它来实现程序的灵活性和可扩展性。
23.职责链模式实战
在这个案例中,我们将使用职责链模式创建一个简单的请假审批流程,包括请假申请和审批人两种对象。具体实现如下:
// 请假申请类
public class LeaveRequest {
private String name;
private int days;
public LeaveRequest(String name, int days) {
this.name = name;
this.days = days;
}
public String getName() {
return name;
}
public int getDays() {
return days;
}
}
// 审批人抽象类
public abstract class Approver {
protected Approver successor;
public void setSuccessor(Approver successor) {
this.successor = successor;
}
public abstract void processRequest(LeaveRequest request);
}
// 经理类
public class Manager extends Approver {
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 3) {
System.out.println("Manager approves the leave request of " + request.getName() + " for " + request.getDays() + " days");
} else if (successor != null) {
successor.processRequest(request);
}
}
}
// 总监类
public class Director extends Approver {
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 5) {
System.out.println("Director approves the leave request of " + request.getName() + " for " + request.getDays() + " days");
} else if (successor != null) {
successor.processRequest(request);
}
}
}
// CEO 类
public class CEO extends Approver {
@Override
public void processRequest(LeaveRequest request) {
if (request.getDays() <= 7) {
System.out.println("CEO approves the leave request of " + request.getName() + " for " + request.getDays() + " days");
} else {
System.out.println("Leave request of " + request.getName() + " for " + request.getDays() + " days is rejected");
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Approver manager = new Manager();
Approver director = new Director();
Approver ceo = new CEO();
manager.setSuccessor(director);
director.setSuccessor(ceo);
LeaveRequest request1 = new LeaveRequest("Alice", 2);
manager.processRequest(request1);
LeaveRequest request2 = new LeaveRequest("Bob", 5);
manager.processRequest(request2);
LeaveRequest request3 = new LeaveRequest("Charlie", 10);
manager.processRequest(request3);
}
}
在这个例子中,我们定义了一个请假申请类 LeaveRequest 和一个审批人抽象类 Approver,它包含了后继审批人 successor 和处理请假申请的方法 processRequest。然后,我们定义了三个具体审批人类 Manager、Director 和 CEO,并实现了它们各自的处理方法。在客户端代码中,我们创建了三个审批人对象,并将它们串成一条审批链,然后创建了三个请假申请对象,并依次提交给经理进行处理。由于审批人是职责链模式的应用,所以我们可以通过它来实现请求的传递和处理,从而简化程序的设计和维护。