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;
@Override
public 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{
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {
//什么也不做
}
}
Mp4Player.java:
javaCopy codepublic class Mp4Player implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
//什么也不做
}
@Override
public 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();
}
}
@Override
public 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反射机制来自动生成代理类,从而简化程序的编写和维护。