Java常用的设计模式有很多种,这些模式有助于解决特定的设计问题,提高代码的可重用性和可维护性。以下是一些常用设计模式的详细介绍:
-
单例模式:确保一个类只有一个实例,并提供一个全局访问点。这对于频繁使用资源的情况特别有用,如数据库连接、线程池等。
“饿汉式”单例模式的示例: public class Singleton { // 在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快 private static Singleton instance = new Singleton(); // 构造函数私有化,防止在其他类中创建此类的实例 private Singleton() {} public static Singleton getInstance() { return instance; } } 另一个是“懒汉式”单例模式的示例: public class Singleton { // 类加载时不初始化 private static Singleton instance; private Singleton() {} // 使用时才初始化,并考虑了线程安全问题 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 注意:上述的“懒汉式”实现是线程安全的,但是每次调用getInstance()都会进行同步,造成不必要的同步开销。如果对该类的实例化操作不频繁,可以考虑使用“双重检查锁定”机制进行优化。这样就可以实现只有在第一次创建对象的时候同步,以后就不需要同步了。这种方式称为双重检查锁定(double-checked locking)。 另外,还可以使用静态内部类、枚举等方式实现单例模式,这些方式都能保证线程安全和懒加载。
-
工厂模式:提供创建对象的接口,但让子类决定要实例化哪个类。这样可以将对象的创建与使用代码分离,降低耦合度。
// 定义产品接口 public interface Product { void use(); } // 具体产品1 public class ConcreteProduct1 implements Product { @Override public void use() { System.out.println("使用具体产品1"); } } // 具体产品2 public class ConcreteProduct2 implements Product { @Override public void use() { System.out.println("使用具体产品2"); } } // 工厂类 public class Factory { // 根据传入的参数决定创建哪个产品 public Product createProduct(String type) { if ("product1".equals(type)) { return new ConcreteProduct1(); } else if ("product2".equals(type)) { return new ConcreteProduct2(); } return null; } } // 客户端代码 public class Client { public static void main(String[] args) { Factory factory = new Factory(); Product product = factory.createProduct("product1"); // 创建产品1 product.use(); // 使用产品1 product = factory.createProduct("product2"); // 创建产品2 product.use(); // 使用产品2 } } 这个示例展示了简单工厂模式的用法。当你需要创建多个不同类型的产品时,可以通过工厂类来创建,而客户端代码则无需关心产品的具体创建过程。这样做的好处是,如果以后需要增加新的产品类型,只需要在工厂类中增加相应的逻辑即可,无需修改客户端代码。这符合开闭原则,即对扩展开放,对修改封闭。
-
观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这在事件驱动编程中很常见。
观察者模式(Observer Pattern)是一种行为型设计模式,它允许对象间建立一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。 下面是一个简单的观察者模式示例: // 主题接口 public interface Subject { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(); } // 具体主题类 public class ConcreteSubject implements Subject { private List<Observer> observers = new ArrayList<>(); private int state; public int getState() { return state; } public void setState(int state) { this.state = state; notifyObservers(); } @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(); } } } // 观察者接口 public interface Observer { void update(); } // 具体观察者类 public class ConcreteObserver implements Observer { private String name; public ConcreteObserver(String name) { this.name = name; } @Override public void update() { System.out.println(name + "收到更新,并执行相应操作!"); } } // 客户端代码 public class Client { public static void main(String[] args) { ConcreteSubject subject = new ConcreteSubject(); ConcreteObserver observer1 = new ConcreteObserver("观察者1"); ConcreteObserver observer2 = new ConcreteObserver("观察者2"); ConcreteObserver observer3 = new ConcreteObserver("观察者3"); subject.registerObserver(observer1); subject.registerObserver(observer2); subject.registerObserver(observer3); System.out.println("状态改变:"); subject.setState(10); // 状态改变,通知所有观察者并更新状态。输出:"观察者1收到更新,并执行相应操作!","观察者2收到更新,并执行相应操作!","观察者3收到更新,并执行相应操作!"。 } } 在这个示例中,当ConcreteSubject的状态通过setState方法改变时,所有注册的ConcreteObserver对象都会通过它们的update方法收到更新通知。这就是观察者模式的工作原理。这种模式在很多场合都非常有用,比如GUI系统中的事件处理、股票交易系统中的价格变动通知等。
-
装饰器模式:动态地给一个对象增加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许你在不改变对象自身的基础上动态地给对象添加职责。装饰器模式提供了与继承相同的功能,但是添加职责的方式更为灵活。 // 组件接口 public interface Component { void operation(); } // 具体组件类 public class ConcreteComponent implements Component { @Override public void operation() { System.out.println("执行具体操作"); } } // 抽象装饰器类,实现了组件接口 public abstract class Decorator implements Component { protected Component component; public Decorator(Component component) { this.component = component; } public void operation() { component.operation(); } } // 具体装饰器类1,增加了一些新的职责 public class ConcreteDecorator1 extends Decorator { public ConcreteDecorator1(Component component) { super(component); } @Override public void operation() { super.operation(); addedFunctionality1(); } public void addedFunctionality1() { System.out.println("执行新增职责1"); } } // 具体装饰器类2,增加了一些新的职责 public class ConcreteDecorator2 extends Decorator { public ConcreteDecorator2(Component component) { super(component); } @Override public void operation() { super.operation(); addedFunctionality2(); } public void addedFunctionality2() { System.out.println("执行新增职责2"); } } // 客户端代码 public class Client { public static void main(String[] args) { Component component = new ConcreteComponent(); // 创建一个具体组件对象 ConcreteDecorator1 decorator1 = new ConcreteDecorator1(component); // 使用具体装饰器1进行装饰 ConcreteDecorator2 decorator2 = new ConcreteDecorator2(decorator1); // 使用具体装饰器2进行装饰 decorator2.operation(); // 执行操作,输出:"执行具体操作","执行新增职责1","执行新增职责2" } } 在这个示例中,我们有一个Component接口和一个具体的ConcreteComponent类。然后我们创建了一个抽象装饰器Decorator,它也实现了Component接口,并持有一个Component的引用。接着我们定义了两个具体装饰器ConcreteDecorator1和ConcreteDecorator2,它们都在operation()方法中添加了自己的职责。最后,在客户端代码中,我们创建了一个ConcreteComponent对象,并使用两个装饰器对其进行装饰。执行操作时,会依次执行所有装饰器添加的职责。
以上只是Java中常用设计模式的一部分,实际上,设计模式的应用和理解需要深入的知识和经验,它们是提高代码质量和效率的重要工具。