JAVA 中常用的设计模式,含案例和注释
工厂模式(Factory Pattern)
工厂模式是一种创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们创建对象而不将创建逻辑暴露给客户端,并使用通用接口引用新创建的对象。
代码示例:
javaCopy code// 定义一个接口
interface Shape {void draw();
}// 定义具体的实现类
class Rectangle implements Shape {public void draw() {System.out.println("Rectangle draw method");}
}class Circle implements Shape {public void draw() {System.out.println("Circle draw method");}
}// 定义一个工厂类
class ShapeFactory {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();}return null;}
}// 使用工厂类创建对象
class FactoryPatternDemo {public static void main(String[] args) {ShapeFactory shapeFactory = new ShapeFactory();// 获取 Circle 的对象,并调用它的 draw 方法Shape shape1 = shapeFactory.getShape("CIRCLE");shape1.draw();// 获取 Rectangle 的对象,并调用它的 draw 方法Shape shape2 = shapeFactory.getShape("RECTANGLE");shape2.draw();}
}
单例模式(Singleton Pattern)
单例模式是一种创建型模式,它确保一个类只有一个实例,并提供对该实例的全局访问点。
代码示例:
javaCopy code// 使用饿汉式实现单例模式
class Singleton {// 创建 Singleton 的一个对象private static Singleton instance = new Singleton();// 让构造函数为 private,这样该类就不会被实例化private Singleton() {}// 获取唯一可用的对象public static Singleton getInstance() {return instance;}public void showMessage() {System.out.println("Hello World!");}
}// 使用 Singleton 类来获取唯一的对象
class SingletonPatternDemo {public static void main(String[] args) {Singleton singleton = Singleton.getInstance();singleton.showMessage();}
}
适配器模式(Adapter Pattern)
适配器模式是一种结构型设计模式,它能够将不兼容的对象包装成适配器对象,从而使得原本因为接口不兼容而无法一起工作的类可以一起工作。
在适配器模式中,有三种角色:
- Target(目标接口):客户端所期望的接口,适配器对象要实现该接口。
- Adaptee(被适配者):需要被适配的对象或类,它定义了客户端不能直接调用的接口。
- Adapter(适配器):将被适配者包装成目标接口的对象。
以下是一个简单的例子,其中 AudioPlayer 是目标接口,MediaPlayer 是被适配者,MediaAdapter 是适配器:
AudioPlayer.java:
javaCopy codepublic class AudioPlayer implements MediaPlayer {MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {//播放 mp3 音乐文件的内置支持if (audioType.equalsIgnoreCase("mp3")) {System.out.println("Playing mp3 file. Name: " + fileName);}//mediaAdapter 提供了播放其他文件格式的支持else if (audioType.equalsIgnoreCase("vlc")|| audioType.equalsIgnoreCase("mp4")) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);}else {System.out.println("Invalid media. " + audioType + " format not supported");}}
}
MediaPlayer.java:
javaCopy codepublic interface MediaPlayer {public void play(String audioType, String fileName);
}
AdvancedMediaPlayer.java:
javaCopy codepublic interface AdvancedMediaPlayer {public void playVlc(String fileName);public void playMp4(String fileName);
}
VlcPlayer.java:
javaCopy codepublic class VlcPlayer implements AdvancedMediaPlayer{@Overridepublic void playVlc(String fileName) {System.out.println("Playing vlc file. Name: "+ fileName);}@Overridepublic void playMp4(String fileName) {//什么也不做}
}
Mp4Player.java:
javaCopy codepublic class Mp4Player implements AdvancedMediaPlayer{@Overridepublic void playVlc(String fileName) {//什么也不做}@Overridepublic void playMp4(String fileName) {System.out.println("Playing mp4 file. Name: "+ fileName);}
}
MediaAdapter.java:
javaCopy codepublic class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType){if(audioType.equalsIgnoreCase("vlc") ){advancedMusicPlayer = new VlcPlayer();}else if (audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {if(audioType.equalsIgnoreCase("vlc")){advancedMusicPlayer.playVlc(fileName);}else if(audioType.equalsIgnoreCase("mp4")){advancedMusicPlayer.playMp4(fileName);}}
}
我们可以使用适配器模式,使得客户端可以通过 AudioPlayer 接口播放 vlc 或 mp4 。
代理模式(Proxy Pattern)
代理模式是一种常见的结构型设计模式,用于在不改变原始类(或对象)代码的情况下,为其提供一种间接的访问方式,从而实现对其行为进行控制或增强。
代理模式主要有三种形式:静态代理、动态代理和虚拟代理。其中,静态代理需要手动编写代理类,而动态代理和虚拟代理则可以使用Java反射机制进行自动生成。
以下是一个使用静态代理模式实现简单的缓存代理的示例代码,其中实现了一个接口UserService
,并通过一个代理类UserServiceProxy
来实现对其方法的缓存代理。
javaCopy code// 定义一个接口
public interface UserService {public void addUser(String userName);
}// 实现接口的原始类
public class UserServiceImpl implements UserService {public void addUser(String userName) {System.out.println("Add user: " + userName);}
}// 代理类,实现了同样的接口,并持有原始类的实例
public class UserServiceProxy implements UserService {private UserService userService;private Map<String, String> cache;public UserServiceProxy(UserService userService) {this.userService = userService;this.cache = new HashMap<>();}// 代理方法,首先从缓存中查找,如果不存在则调用原始类方法,并将结果放入缓存public void addUser(String userName) {if (cache.containsKey(userName)) {System.out.println("User " + userName + " already exists.");} else {userService.addUser(userName);cache.put(userName, userName);System.out.println("User " + userName + " added.");}}
}// 使用代理类
public class Client {public static void main(String[] args) {UserService userService = new UserServiceImpl();UserServiceProxy proxy = new UserServiceProxy(userService);proxy.addUser("Tom");proxy.addUser("Jerry");proxy.addUser("Tom"); // 从缓存中获取}
}
在上述示例代码中,UserServiceProxy
类是一个代理类,它实现了UserService
接口,并持有一个UserService
类型的实例。在代理类中实现了addUser
方法,首先从缓存中查找是否已存在该用户,如果存在则直接返回,否则调用原始类UserServiceImpl
的addUser
方法,并将结果放入缓存。这样,在使用代理类时,就可以自动实现对方法的缓存代理,从而提高程序的运行效率。
需要注意的是,以上示例中的代理模式为静态代理模式,需要手动编写代理类。如果需要实现动态代理或虚拟代理,则可以使用Java反射机制来自动生成代理类,从而简化程序的编写和维护。