设计模式是解决特定问题的固定方法,它描述了如何解决常见设计问题的最佳实践。在Java中,32种设计模式通常分为三类:创建型模式、结构型模式和行为型模式。
-
创建型模式(5种):这些设计模式提供了一种在创建对象时的最佳实践。
- 单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。
- 建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- 原型模式(Prototype):用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
- 工厂方法模式(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。
- 抽象工厂模式(Abstract Factory):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
-
结构型模式(7种):这些设计模式关注类和对象的组合,以形成更大的结构。
- 适配器模式(Adapter):将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 桥接模式(Bridge):将抽象部分与它的实现部分分离,使它们都可以独立地变化。
- 组合模式(Composite):将对象组合成树形结构以表示"部分-整体"的层次结构,使得客户对单个对象和复合对象的使用具有一致性。
- 装饰器模式(Decorator):动态地给一个对象增加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更为灵活。
- 外观模式(Facade):为子系统中的一组接口提供一个一致的界面,此界面使得这一子系统更加容易使用。
- 享元模式(Flyweight):运用共享技术有效地支持大量细粒度的对象。
- 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
-
行为型模式(20种):这些设计模式特别关注对象之间的通信。
- 责任链模式(Chain of Responsibility):为避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
- 命令模式(Command):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销操作。
- 解释器模式(Interpreter):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
- 迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示。
- 中介者模式(Mediator):用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
- 备忘录模式(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。
- 观察者模式(Observer):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 状态模式(State):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了自身。
- 策略模式(Strategy):定义一系列的算法,并且把每一个算法封装起来,使它们可以互相替换,让算法独立于使用它的客户。
- 模板方法模式(Template Method):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
- 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
以上就是Java中的32种设计模式。这些模式是面向对象设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
这里选取几个经典的设计模式进行讲解:
- 单例模式(Singleton)
单例模式确保一个类只有一个实例,并提供一个全局访问点。
csharp
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 观察者模式(Observer)
观察者模式定义了一种一对多的依赖关系,让多个观察者对象能够同时监听某一个主题对象的状态变化。
csharp
public interface Observer {
void update();
}
public class Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
- 装饰者模式(Decorator)
装饰者模式动态地给一个对象增加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更为灵活。
csharp
public interface Shape {
void draw();
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing a rectangle...");
}
}
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape) {
this.decoratedShape = decoratedShape;
}
@Override
public void draw() {
decoratedShape.draw();
}
}
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder();
}
private void setRedBorder() {
System.out.println("Setting red border...");
}
}
4.下面是一个简单的工厂方法模式的示例:
首先,定义一个产品接口 Product
:
csharp
public interface Product {
void use();
}
然后,实现两个具体的产品类 ConcreteProduct1
和 ConcreteProduct2
:
typescript
public class ConcreteProduct1 implements Product {
@Override
public void use() {
System.out.println("Using ConcreteProduct1...");
}
}
public class ConcreteProduct2 implements Product {
@Override
public void use() {
System.out.println("Using ConcreteProduct2...");
}
}
接下来,定义工厂接口 Factory
:
csharp
public interface Factory {
Product createProduct();
}
然后,实现两个具体的工厂类 ConcreteFactory1
和 ConcreteFactory2
,分别用于创建 ConcreteProduct1
和 ConcreteProduct2
:
typescript
public class ConcreteFactory1 implements Factory {
@Override
public Product createProduct() {
return new ConcreteProduct1();
}
}
public class ConcreteFactory2 implements Factory {
@Override
public Product createProduct() {
return new ConcreteProduct2();
}
}
最后,编写客户端代码:
ini
public class Client {
public static void main(String[] args) {
Factory factory1 = new ConcreteFactory1();
Product product1 = factory1.createProduct();
product1.use();
Factory factory2 = new ConcreteFactory2();
Product product2 = factory2.createProduct();
product2.use();
}
}
在这个示例中,我们定义了一个产品接口 Product
和两个具体的产品类 ConcreteProduct1
和 ConcreteProduct2
。我们还定义了一个工厂接口 Factory
和两个具体的工厂类 ConcreteFactory1
和 ConcreteFactory2
。客户端代码通过工厂对象创建产品对象,并调用其 use
方法。这样,我们可以根据需要选择创建不同的产品对象,而无需直接依赖于具体的产品类。这就是工厂方法模式的核心思想。
设计模式的选择使用应该根据具体情况进行权衡和决策。以下是一些指导原则,帮助你在选择设计模式时做出合适的选择:
- 理解问题场景和需求:在选择设计模式之前,首先要深入理解问题场景和需求。分析问题的本质和特点,明确目标和约束,为选择合适的设计模式奠定基础。
- 了解设计模式的适用场景:每种设计模式都有其适用的场景和解决的问题。在学习和使用设计模式时,要清楚每种模式的使用条件和效果,以便将其应用于合适的场景中。
- 根据经验和最佳实践进行选择:借鉴他人的经验和最佳实践是选择设计模式的重要途径。参考专业书籍、学术论文、开源项目等资源,了解其他开发者在处理类似问题时的选择和使用情况。
- 考虑可扩展性和可维护性:在选择设计模式时,要考虑系统的可扩展性和可维护性。优先选择那些能够降低耦合度、提高代码重用性、方便扩展和维护的设计模式。
- 不要过度设计:避免在没有明确需求或问题复杂度不高的情况下过度使用设计模式。过度设计可能导致代码结构复杂,增加不必要的开发和维护成本。保持简单和清晰是设计的重要原则。
- 结合实际情况进行调整:设计模式提供的是一种通用的解决方案,但在实际应用中可能需要根据具体情况进行调整和改进。在使用设计模式时,要保持灵活性和开放心态,根据实际情况进行适当的调整和优化。
总之,选择合适的设计模式需要综合考虑问题场景、需求、经验、可扩展性、可维护性等因素。通过深入理解问题、学习模式的应用场景、借鉴经验和最佳实践,以及保持简单和灵活的心态,你将能够更好地选择和使用设计模式来解决实际问题。
使用Java中的设计模式有以下几个原因:
- 提高代码可重用性和可维护性:设计模式提供了一套通用的解决方案,可以应用于不同的问题场景。通过使用设计模式,我们可以避免重复编写类似的代码逻辑,提高了代码的可重用性。同时,设计模式通常都经过时间的考验和验证,它们的代码结构清晰、易于理解,有助于减少维护成本和提高代码的可维护性。
- 改善代码质量和可读性:设计模式是由经验丰富的软件开发者总结和提炼出来的最佳实践,它们经过了长期的验证和改进,代表了高质量的代码设计。通过使用设计模式,我们可以改善代码的质量,并提高代码的可读性。设计模式通常都有明确的命名和结构化的代码实现,这使得其他开发者能够更快地理解代码的逻辑和功能。
- 提高系统的灵活性和可扩展性:设计模式可以帮助我们设计出更加灵活和可扩展的系统。它们提供了一种机制,可以在不修改现有代码的情况下,方便地扩展系统的功能和行为。这对于应对需求变更和快速迭代开发的场景尤为重要。通过使用设计模式,我们可以降低系统的耦合度,并提高系统的可配置性和可插件化能力。
- 促进团队协作和交流:设计模式的学习和使用可以促进团队之间的协作和交流。当团队成员都熟悉并遵循相同的设计模式时,他们可以更加高效地理解和修改彼此的代码。设计模式提供了一种通用的语言,使得团队成员能够更顺畅地沟通和协作,提高团队的整体效能。
综上所述,使用Java中的设计模式有助于提高代码的可重用性和可维护性,改善代码质量和可读性,提高系统的灵活性和可扩展性,以及促进团队协作和交流。