设计模式
设计模式
设计模式是指在软件设计中常常遇到的一些重复性问题所提供的可复用解决方案,它能够帮忙咱们进步软件的可维护性、可扩展性和可重用性。Java 中的设计模式是基于面向对象编程思维而产生的,它们能够帮忙咱们更好地组织代码并升高代码的耦合度。
根本准则
Java 中的设计模式基于以下根本准则:
- 繁多职责准则
- 凋谢关闭准则
- 里氏替换准则
- 依赖倒置准则
- 接口隔离准则
- 迪米特法令
常见的设计模式
Java 中常见的设计模式包含:
- 工厂模式
- 单例模式
- 原型模式
- 适配器模式
- 装璜器模式
- 代理模式
- 观察者模式
- 责任链模式
- 命令模式
- 模板办法模式
- 策略模式
设计模式是面向对象编程中十分重要的一个概念,它能够帮忙咱们更好地组织代码并进步代码的可维护性和可扩展性。在理论利用中,咱们应该依据须要抉择适合的设计模式来解决问题,防止适度应用设计模式导致代码复杂度减少。
根本准则介绍
繁多职责准则
繁多职责准则(SRP)是指一个类或模块只负责实现一个职责或性能。如果一个类或模块承当了多个职责或性能,那么它的职责和性能就会变得不清晰,容易呈现 bug,并且难以保护和扩大。
Java 示例代码:
public class UserService {public void register(User user) {// 注册用户}
public void login(User user) {// 登录用户}
public void updateUser(User user) {// 更新用户信息}
public void deleteUser(User user) {// 删除用户}
}
在下面的示例代码中,UserService
类负责用户的注册、登录、更新和删除这四个职责,这违反了繁多职责准则。咱们能够将其拆分为四个类,每个类只负责一个职责。
凋谢关闭准则
凋谢关闭准则(OCP)是指一个软件实体应该对扩大凋谢,对批改敞开。也就是说,在不批改原有代码的状况下,通过扩大它来实现新的性能。
Java 示例代码:
public interface Shape {void draw();
}
public class Rectangle implements Shape {
@Override
public void draw() {System.out.println("Drawing rectangle");
}
}
public class Circle implements Shape {
@Override
public void draw() {System.out.println("Drawing circle");
}
}
public class ShapeDrawer {private List<Shape> shapes = new ArrayList<>();
public void addShape(Shape shape) {shapes.add(shape);
}
public void drawShapes() {for (Shape shape : shapes) {shape.draw();
}
}
}
在下面的示例代码中,Shape
接口示意图形,Rectangle
和 Circle
类别离实现了 Shape
接口。ShapeDrawer
类负责绘制图形,其中 addShape
办法用于增加图形,drawShapes
办法用于绘制所有图形。如果咱们须要新增一种图形,只须要创立一个新的类,实现 Shape
接口,并增加到 ShapeDrawer
中即可,不须要批改原有代码。
里氏替换准则
里氏替换准则(LSP)是指在任何能够应用基类对象的中央,肯定能够应用子类对象来替换。也就是说,子类应该可能替换掉父类并且不会影响程序的正确性。
Java 示例代码:
public class Vehicle {public void run() {System.out.println("Vehicle is running");
}
}
public class Car extends Vehicle {
@Override
public void run() {System.out.println("Car is running");
}
}
public class Bike extends Vehicle {
@Override
public void run() {System.out.println("Bike is running");
}
}
在下面的示例代码中,Vehicle
类示意车辆,Car
和 Bike
类别离继承自 Vehicle
类。因为 Car
和Bike
类继承自 Vehicle
类,所以它们能够替换 Vehicle
类的对象,并且不会影响程序的正确性。
依赖倒置准则
依赖倒置准则(DIP)是指高层模块不应该依赖于低层模块,它们应该依赖于形象。同时,形象不应该依赖于具体实现,具体实现应该依赖于形象。
Java 示例代码:
public interface MessageSender {void send(String message);
}
public class EmailSender implements MessageSender {
@Override
public void send(String message) {System.out.println("Sending email:" + message);
}
}
public class SmsSender implements MessageSender {
@Override
public void send(String message) {System.out.println("Sending SMS:" + message);
}
}
public class NotificationService {
private MessageSender messageSender;
public NotificationService(MessageSender messageSender) {this.messageSender = messageSender;}
public void sendNotification(String message) {messageSender.send(message);
}
}
在下面的示例代码中,MessageSender
接口示意音讯发送器,EmailSender
和 SmsSender
类别离实现了 MessageSender
接口。NotificationService
类示意告诉服务,其中的 sendNotification
办法能够发送告诉,它通过 MessageSender
接口与具体的音讯发送器解耦。这样,咱们能够在不批改 NotificationService
类的状况下,通过传递不同的 MessageSender
对象来实现不同的音讯发送形式。
接口隔离准则
接口隔离准则(ISP)是指一个类对另一个类的依赖应该建设在最小的接口上。也就是说,不应该强制一个类依赖于它不须要的办法。
Java 示例代码:
public interface Payment {void pay();
}
public class CreditCardPayment implements Payment {
@Override
public void pay() {System.out.println("Paying with credit card");
}
}
public class CashPayment implements Payment {
@Override
public void pay() {System.out.println("Paying with cash");
}
}
public class ShoppingCart {private List<Payment> payments = new ArrayList<>();
public void addPayment(Payment payment) {payments.add(payment);
}
public void checkout() {for (Payment payment : payments) {payment.pay();
}
}
}
在下面的示例代码中,Payment
接口示意领取形式,CreditCardPayment
和 CashPayment
类别离实现了 Payment
接口。ShoppingCart
类示意购物车,其中的 addPayment
办法用于增加领取形式,checkout
办法用于结账。因为 ShoppingCart
类依赖于 Payment
接口,所以咱们能够依据须要增加不同的领取形式,而不须要强制 ShoppingCart
类依赖于它不须要的办法。
迪米特法令
迪米特法令(LKP)是指一个对象应该对其余对象有起码的理解。也就是说,一个对象应该尽量减少与其余对象之间的交互,只和本人的间接敌人交互。
Java 示例代码:
public class Teacher {
private String name;
public Teacher(String name) {this.name = name;}
public String getName() {return name;}
}
public class Course {
private Teacher teacher;
public Course(Teacher teacher) {this.teacher = teacher;}
public void printTeacherName() {System.out.println(teacher.getName());
}
}
public class School {private List<Course> courses = new ArrayList<>();
public void addCourse(Course course) {courses.add(course);
}
public void printCourseTeacherNames() {for (Course course : courses) {course.printTeacherName();
}
}
}
在下面的示例代码中,Teacher
类示意老师,Course
类示意课程,School
类示意学校。因为 Course
类只依赖于 Teacher
类,而不依赖于 School
类,所以咱们能够在不批改 Course
类的状况下,将其增加到 School
类中,并调用 printCourseTeacherNames
办法打印所有课程的老师名字。
Java 中常见的设计模式
工厂模式
工厂模式是一种创立型设计模式,它提供了一种创建对象的形式,而无需裸露对象的创立逻辑。工厂模式有多种实现形式,最常见的有简略工厂模式、工厂办法模式、形象工厂模式。
简略工厂模式
简略工厂模式是最简略的工厂模式,它将对象的创立逻辑封装在一个工厂类中,客户端只须要调用工厂类的静态方法来获取对象实例。以下是一个简略工厂模式的 Java 代码示例:
// 形象产品类
public interface Product {void use();
}
// 具体产品类 A
public class ConcreteProductA implements Product {
@Override
public void use() {System.out.println("Using product A.");
}
}
// 具体产品类 B
public class ConcreteProductB implements Product {
@Override
public void use() {System.out.println("Using product B.");
}
}
// 工厂类
public class SimpleFactory {public static Product createProduct(String type) {switch (type) {
case "A":
return new ConcreteProductA();
case "B":
return new ConcreteProductB();
default:
throw new IllegalArgumentException("Invalid product type.");
}
}
}
// 客户端代码
public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");
Product productB = SimpleFactory.createProduct("B");
productA.use(); // Using product A.
productB.use(); // Using product B.}
}
在这个示例中,工厂类 SimpleFactory 提供了一个静态方法 createProduct()来创立产品实例,客户端只须要调用这个办法并传入产品类型参数即可。在 createProduct()办法中,依据不同的产品类型返回不同的具体产品实例。
工厂办法模式
工厂办法模式是一种更加灵便的工厂模式,它将对象的创立提早到子类中实现,客户端只须要针对形象工厂和形象产品编程,而无需晓得具体的实现类。以下是一个工厂办法模式的 Java 代码示例:
// 形象产品类
public interface Product {void use();
}
// 具体产品类 A
public class ConcreteProductA implements Product {
@Override
public void use() {System.out.println("Using product A.");
}
}
// 具体产品类 B
public class ConcreteProductB implements Product {
@Override
public void use() {System.out.println("Using product B.");
}
}
// 形象工厂类
public interface Factory {Product createProduct();
}
// 具体工厂类 A
public class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {return new ConcreteProductA();
}
}
// 具体工厂类 B
public class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {return new ConcreteProductB();
}
}
// 客户端代码
public class Client {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();
Factory factoryB = new ConcreteFactoryB();
Product productA = factoryA.createProduct();
Product productB = factoryB.createProduct();
productA.use(); // Using product A.
productB.use(); // Using product B.}
}
在这个示例中,形象工厂类 Factory 定义了一个形象办法 createProduct(),具体工厂类 ConcreteFactoryA 和 ConcreteFactoryB 别离实现了这个办法来创立具体产品实例。客户端代码针对形象工厂和形象产品编程,通过具体工厂类的实例来创立具体产品实例。
形象工厂模式
形象工厂模式是一种提供多个工厂办法的工厂模式,它能够创立一组相干或相互依赖的对象。形象工厂模式通常须要定义多个形象产品类和多个形象工厂类,每个形象工厂类负责创立一组相干的具体产品。以下是一个形象工厂模式的 Java 代码示例:
// 形象产品类 Apublic interface ProductA {void use();
}
// 具体产品类 A1public class ConcreteProductA1 implements ProductA {
@Override
public void use() {System.out.println("Using product A1.");
}
}
// 具体产品类 A2public class ConcreteProductA2 implements ProductA {
@Override
public void use() {System.out.println("Using product A2.");
}
}
// 形象产品类 Bpublic interface ProductB {void eat();
}
// 具体产品类 B1public class ConcreteProductB1 implements ProductB {
@Override
public void eat() {System.out.println("Eating product B1.");
}
}
// 具体产品类 B2public class ConcreteProductB2 implements ProductB {
@Override
public void eat() {System.out.println("Eating product B2.");
}
}
// 形象工厂类 public interface Factory {ProductA createProductA();
ProductB createProductB();}
// 具体工厂类 1public class ConcreteFactory1 implements Factory {
@Override
public ProductA createProductA() {return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {return new ConcreteProductB1();
}
}
// 具体工厂类 2public class ConcreteFactory2 implements Factory {
@Override
public ProductA createProductA() {return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {return new ConcreteProductB2();
}
}
// 客户端代码 public class Client {public static void main(String[] args) {Factory factory1 = new ConcreteFactory1();
Factory factory2 = new ConcreteFactory2();
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA1.use();// Using product A1.
productB1。eat();// Eating product B1.
productA2.use();// Using product A2.
productB2.eat();// Eating product B2.}
}
在这个示例中,形象工厂类 Factory 定义了两个形象办法 createProductA()和 createProductB(),具体工厂类 ConcreteFactory1 和 ConcreteFactory2 别离实现了这两个办法来创立一组相干的具体产品。客户端代码通过具体工厂类的实例来创立具体产品实例,每个工厂类只创立本人对应的产品实例。
单例模式
单例模式是一种创立型设计模式,它保障一个类只有一个实例,并提供了一个全局拜访点供内部代码获取该实例。单例模式通常须要满足三个条件:私有化构造函数、提供一个静态方法获取实例、保障只有一个实例存在。
懒汉式
以下是一个应用懒汉式实现的单例模式的 Java 代码示例:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {if (instance == null) {instance = new Singleton();
}
return instance;
}
}
在这个示例中,Singleton 类的构造函数是公有的,这意味着内部代码不能通过实例化 Singleton 类来创立新的对象。Singleton 类提供了一个静态方法 getInstance()来获取 Singleton 类的惟一实例。在 getInstance()办法中,如果还没有创立实例,就会创立一个新实例并返回,否则间接返回已有的实例。
须要留神的是,这种懒汉式实现的单例模式在多线程环境下可能会存在线程平安问题。能够通过加锁或应用双重查看锁定等形式来解决这个问题。
饿汉式
在这种实现形式中,单例对象在类加载的时候就曾经创立好了,因而不存在线程平安问题,然而可能会节约一些内存空间。
public class Singleton {private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {return instance;}
}
双重查看锁定
这种实现形式通过双重查看锁定来保障线程平安和性能,它提早了对象的创立工夫,只有在第一次拜访单例对象时才创立实例。
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();
}
}
}
return instance;
}
}
动态外部类
这种实现形式通过动态外部类来提早单例对象的创立工夫,它既保证了线程平安,又防止了饿汉式实现形式的内存节约问题。
public class Singleton {private Singleton() {}
private static class SingletonHolder {private static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {return SingletonHolder.instance;}
}
枚举
这种实现形式利用枚举的个性来保障单例对象的唯一性,它既简略又平安。
public enum Singleton {
INSTANCE;
public void doSomething() {// ...}
}
原型模式
原型模式是一种创立型设计模式,它容许通过复制现有对象来创立新对象,而无需通过实例化来创建对象。原型模式在创立简单对象的场景下十分有用,能够防止反复创立雷同的对象,进步对象创立的效率。
以下是一个原型模式的 Java 代码示例:
public abstract class Prototype implements Cloneable {public abstract Prototype clone();
}
public class ConcretePrototype extends Prototype {
private String field1;
private int field2;
public ConcretePrototype(String field1, int field2) {
this.field1 = field1;
this.field2 = field2;
}
public String getField1() {return field1;}
public void setField1(String field1) {this.field1 = field1;}
public int getField2() {return field2;}
public void setField2(int field2) {this.field2 = field2;}
@Override
public Prototype clone() {return new ConcretePrototype(field1, field2);
}
}
在这个示例中,Prototype 是原型类,定义了一个形象办法 clone(),该办法用于复制原型对象。ConcretePrototype 是具体原型类,实现了原型类的 clone()办法,并定义了本人的属性和办法。
在工业软件开发中,原型模式经常用于对象的复制和初始化。例如,在制造业中,产品的制作须要经验一系列的工艺流程,每个工艺流程都须要对产品进行加工和解决。如果每次都从新创立一个产品对象,那么就会节约很多工夫和资源。通过原型模式,能够在第一次创立产品对象时,将其复制为原型对象,并在每个工艺流程中复制原型对象,而后对复制后的对象进行加工和解决,这样就能够防止反复创建对象的问题,进步了加工效率。另外,在设计 CAD 软件时,也能够应用原型模式来实现图形对象的复制和粘贴性能。当用户抉择复制一个图形对象时,能够将该对象作为原型对象,并将其复制到剪贴板中。当用户抉择粘贴操作时,能够从剪贴板中获取原型对象,并将其复制一份作为新的图形对象,而后将其插入到画布中。这样就能够防止反复创立雷同的图形对象,进步了图形操作的效率。
适配器模式
适配器模式是一种结构型设计模式,它容许不兼容的接口之间进行合作。适配器模式通过创立一个两头适配器来转换一个接口为另一个接口,从而使得本来不兼容的接口可能协同工作。
以下是一个适配器模式的 Java 代码示例:
public interface Target {void request();
}
public class Adaptee {public void specificRequest() {// ...}
}
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}
@Override
public void request() {adaptee.specificRequest();
}
}
在这个示例中,Target 是指标接口,定义了一个 request()办法。Adaptee 是被适配的类,其中蕴含一个 specificRequest()办法。Adapter 是适配器类,它实现了 Target 接口,并蕴含一个 Adaptee 对象。在 Adapter 的 request()办法中,调用 Adaptee 对象的 specificRequest()办法来实现指标接口的申请。
常见的应用场景:
- 旧接口与新接口的适配:当零碎须要应用一个老接口然而只有新接口可用时,能够应用适配器模式将新接口转换为老接口。这种状况通常产生在零碎的降级和改良中。
- 内部接口与外部接口的适配:当零碎须要应用一个内部接口,然而该接口与外部接口不兼容时,能够应用适配器模式将内部接口转换为外部接口。这种状况通常产生在零碎与第三方库或服务集成时。
- 多个接口之间的适配:当零碎须要应用多个不兼容的接口进行协同工作时,能够应用适配器模式将这些接口转换为对立的接口。这种状况通常产生在零碎须要与多个内部零碎协同工作时。
总之,适配器模式能够帮忙咱们在不扭转现有零碎接口的状况下,实现不同接口之间的协同工作,进步零碎的可扩展性和灵活性。
装璜器模式
装璜器模式是一种结构型设计模式,容许你通过将对象放入包装对象中来为原对象增加新的行为。装璜器模式能够在不批改原始对象的状况下,动静地增加性能。
Java 代码示例:
// 定义一个接口 public interface Shape {void draw();
}
// 创立一个实现接口的实体类 public class Rectangle implements Shape {
@Override
public void draw() {System.out.println("Shape: Rectangle");
}
}
// 创立一个装璜器类,实现同样的接口 public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){this.decoratedShape = decoratedShape;}
public void draw(){decoratedShape.draw();
}
}
// 创立扩大了 ShapeDecorator 类的实体装璜类 public class RedShapeDecorator extends ShapeDecorator {public RedShapeDecorator(Shape decoratedShape) {super(decoratedShape);
}
@Override
public void draw() {decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){System.out.println("Border Color: Red");
}
}
// 应用装璜器 public class DecoratorPatternDemo {public static void main(String[] args) {Shape rectangle = new Rectangle();
Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Normal Rectangle:");
rectangle.draw();
System.out.println("\nRed Rectangle:");
redRectangle.draw();}
}
在软件开发中,装璜器模式通常利用于以下场景:
- 当须要动静地为对象增加性能或行为时,能够应用装璜器模式。这种形式比继承更加灵便,因为它能够在运行时动静地增加或删除性能。
- 当不能采纳继承形式对对象进行扩大时,能够应用装璜器模式。例如,当类曾经被定义为 final 时,就无奈通过继承形式进行扩大,此时能够应用装璜器模式来增加新的行为。
- 当须要在不影响其余对象的状况下,对单个对象进行批改或扩大时,能够应用装璜器模式。这种形式防止了在批改对象时对其余对象造成影响。
- 在 GUI 程序设计中,装璜器模式罕用于为控件增加新的行为或外观。例如,能够应用装璜器模式为按钮增加边框、背景色彩等成果,而不须要对按钮自身进行批改。
代理模式
代理模式是一种结构型设计模式,它容许你提供一个代理对象,以管制对其它对象的拜访。
在代理模式中,代理对象领有与理论对象雷同的接口,客户端无需晓得理论对象的存在,只须要与代理对象进行交互。代理对象在须要时将申请转发给理论对象,并在必要时执行一些额定的逻辑。
上面是一个简略的 Java 代码示例:
interface Image {void display();
}
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk(filename);
}
public void display() {System.out.println("Displaying" + filename);
}
private void loadFromDisk(String filename) {System.out.println("Loading" + filename);
}
}
class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {this.filename = filename;}
public void display() {if (realImage == null) {realImage = new RealImage(filename);
}
realImage.display();}
}
public class Main {public static void main(String[] args) {Image image = new ProxyImage("test.jpg");
image.display();}
}
在这个示例中,Image
是一个接口,RealImage
是实现它的具体类,ProxyImage
是实现了 Image
接口的代理类。
代理类在 display()
办法中查看理论对象是否曾经被创立,如果没有,它将创立一个并调用其 display()
办法。如果理论对象曾经存在,代理类将间接调用它的 display()
办法。
代理模式在软件开发中的场景举例:
- 近程代理:在客户端和服务器之间应用近程代理,客户端通过近程代理拜访服务器上的对象。
- 虚构代理:在必要时,应用虚构代理来提早理论对象的创立,以进步性能和缩小资源耗费。例如,当须要加载大型图像或视频文件时,能够应用虚构代理来防止在初始化时加载所有数据。
- 平安代理:在拜访敏感对象时,应用平安代理来管制对对象的拜访。例如,只有通过身份验证的用户能力拜访某些对象。
- 缓存代理:在拜访频繁的对象时,应用缓存代理来缓存对象的后果,防止反复计算。例如,在计算简单数学函数时,能够应用缓存代理来存储曾经计算过的后果,以进步性能。
- 日志记录代理:在拜访对象时,应用日志记录代理来记录拜访日志,以便后续剖析和调试。例如,在调试时,能够应用日志记录代理来记录对象的拜访和参数。
观察者模式
观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态产生扭转时,所有依赖它的对象都会收到告诉并自动更新。
以下是一个观察者模式的 Java 代码示例:
public interface Observer {void update(int data);
}
public interface Subject {void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();}
public class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();
private int data;
@Override
public void attach(Observer observer) {observers.add(observer);
}
@Override
public void detach(Observer observer) {observers.remove(observer);
}
@Override
public void notifyObservers() {for (Observer observer : observers) {observer.update(data);
}
}
public void setData(int data) {
this.data = data;
notifyObservers();}
}
public class ConcreteObserver implements Observer {
private int data;
@Override
public void update(int data) {
this.data = data;
System.out.println("Observer received data:" + data);
}
}
在这个示例中,Observer 是观察者接口,定义了一个 update()办法。Subject 是主题接口,定义了 attach()、detach()和 notifyObservers()办法。ConcreteSubject 是具体主题类,实现了 Subject 接口,并蕴含一个观察者列表和一个数据字段。在 ConcreteSubject 中,当数据发生变化时,通过 notifyObservers()办法告诉所有的观察者。ConcreteObserver 是具体观察者类,实现了 Observer 接口,并在 update()办法中打印出接管到的数据。
观察者模式在软件开发过程中的场景举例:
- GUI 组件
在 GUI 组件中,用户界面通常须要依据某些状态或事件的变动来更新界面。例如,在一个文本编辑器中,当用户输出文本时,文本区域和状态栏都须要实时更新。这时,能够应用观察者模式来实现状态和界面之间的同步。
- 数据库操作
在数据库操作中,当数据库中的某些数据发生变化时,须要及时告诉其余零碎或组件进行相应的解决。例如,在一个电商网站中,当用户下单购买商品时,须要更新库存和订单信息。这时,能够应用观察者模式来实现库存和订单之间的同步。
- 网络通信
在网络通信中,当一个节点的状态发生变化时,须要及时告诉其余节点进行相应的解决。例如,在一个分布式系统中,当一个节点产生故障时,其余节点须要及时接管该节点的工作和数据。这时,能够应用观察者模式来实现节点之间的同步和协同工作。
总之,观察者模式能够帮忙咱们实现对象之间的松耦合和同步,进步零碎的可维护性和可扩展性。
责任链模式
责任链模式是一种行为型设计模式,它容许多个对象都有机会解决申请,从而防止申请的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该申请,直到有一个对象解决它为止。
Java 代码示例:
// 定义一个形象处理器 public abstract class AbstractLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
// 责任链中的下一个元素 protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger){this.nextLogger = nextLogger;}
public void logMessage(int level, String message){if(this.level <= level){write(message);
}
if(nextLogger !=null){nextLogger.logMessage(level, message);
}
}
abstract protected void write(String message);
}
// 创立扩大了 AbstractLogger 的实体类 public class ConsoleLogger extends AbstractLogger {public ConsoleLogger(int level){this.level = level;}
@Override
protected void write(String message) {System.out.println("Standard Console::Logger:" + message);
}
}
public class ErrorLogger extends AbstractLogger {public ErrorLogger(int level){this.level = level;}
@Override
protected void write(String message) {System.out.println("Error Console::Logger:" + message);
}
}
public class FileLogger extends AbstractLogger {public FileLogger(int level){this.level = level;}
@Override
protected void write(String message) {System.out.println("File::Logger:" + message);
}
}
// 应用责任链模式 public class ChainPatternDemo {public static void main(String[] args) {AbstractLogger loggerChain = getChainOfLoggers();
loggerChain.logMessage(AbstractLogger.INFO, "This is an information.");
loggerChain.logMessage(AbstractLogger.DEBUG, "This is a debug level information.");
loggerChain.logMessage(AbstractLogger.ERROR, "This is an error information.");
}
private static AbstractLogger getChainOfLoggers(){AbstractLogger errorLogger = newErrorLogger(AbstractLogger.ERROR);
AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
errorLogger.setNextLogger(fileLogger);
fileLogger.setNextLogger(consoleLogger);
return errorLogger;
}
}
场景举例:
在软件开发中,责任链模式通常利用于以下场景:
- 当须要将申请发送给多个对象时,能够应用责任链模式。例如,一个异样能够被多个异样处理程序解决,且每个处理程序只负责解决特定类型的异样。
- 当不确定哪个对象应该解决申请时,能够应用责任链模式。例如,一个申请可能须要依据不同的条件由不同的处理程序解决。
- 当须要动静地增加或删除处理程序时,能够应用责任链模式。这种形式能够让用户增加或删除处理程序,而不须要批改代码。
- 当须要将申请从一个对象传递到另一个对象时,能够应用责任链模式。例如,在一个分布式系统中,能够应用责任链模式将申请从一个节点传递到另一个节点,直到找到可能解决申请的节点为止。
命令模式
命令模式是一种行为型设计模式,它容许你将申请封装为一个对象,并将其传递给不同的对象进行调用。
在命令模式中,命令对象封装了一个申请和相干的参数,能够将其传递给调用者,调用者无需晓得申请的具体实现,只须要调用命令对象的执行办法即可。
上面是一个简略的 Java 代码示例:
interface Command {void execute();
}
class Light {public void turnOn() {System.out.println("Light is on");
}
public void turnOff() {System.out.println("Light is off");
}
}
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {this.light = light;}
public void execute() {light.turnOn();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {this.light = light;}
public void execute() {light.turnOff();
}
}
class RemoteControl {
private Command command;
public void setCommand(Command command) {this.command = command;}
public void pressButton() {command.execute();
}
}
public class Main {public static void main(String[] args) {Light light = new Light();
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);
RemoteControl remoteControl = new RemoteControl();
remoteControl.setCommand(lightOnCommand);
remoteControl.pressButton();
remoteControl.setCommand(lightOffCommand);
remoteControl.pressButton();}
}
在这个示例中,Command
是一个接口,LightOnCommand
和 LightOffCommand
实现了它。RemoteControl
类持有一个 Command
对象,并在调用 pressButton()
办法时执行该对象的 execute()
办法。
命令模式在软件开发中的场景举例:
- 网络申请队列:在解决网络申请时,能够将申请封装为命令对象,将其退出到申请队列中,而后异步执行。这能够缩小网络申请的提早和进步零碎的响应速度。
- 撤销和重做性能:在实现撤销和重做性能时,能够应用命令模式来记录操作历史,每个命令对象都能够记录其执行前和执行后的状态,并实现撤销和重做办法。
- 菜单零碎:在实现菜单零碎时,能够将每个菜单项封装为命令对象,而后将其增加到菜单中。当用户抉择菜单项时,菜单对象将调用相应的命令对象。
- 日志记录:在记录零碎操作日志时,能够应用命令模式来记录每个操作,包含其执行工夫、执行者和执行后果等信息。
- 队列零碎:在实现队列零碎时,能够将每个工作封装为命令对象,并将其退出到队列中。队列零碎将异步执行每个工作,并且能够动静增加或删除工作。
模板办法
模板办法模式是一种行为型设计模式,它定义了一个算法的骨架,将算法中不变的局部形象进去,而将可变的局部留给子类来实现。模板办法模式使得子类能够在不扭转算法构造的状况下,从新定义算法的某些步骤。
以下是一个模板办法模式的 Java 代码示例:
public abstract class AbstractClass {public final void templateMethod() {operation1();
operation2();
if (hook()) {operation3();
}
}
protected abstract void operation1();
protected abstract void operation2();
protected void operation3() {}
protected boolean hook() {return true;}
}
public class ConcreteClass1 extends AbstractClass {
@Override
protected void operation1() {System.out.println("ConcreteClass1: operation1");
}
@Override
protected void operation2() {System.out.println("ConcreteClass1: operation2");
}
}
public class ConcreteClass2 extends AbstractClass {
@Override
protected void operation1() {System.out.println("ConcreteClass2: operation1");
}
@Override
protected void operation2() {System.out.println("ConcreteClass2: operation2");
}
@Override
protected void operation3() {System.out.println("ConcreteClass2: operation3");
}
@Override
protected boolean hook() {return false;}
}
在这个示例中,AbstractClass 是形象模板类,定义了一个 templateMethod()办法,其中蕴含了若干个操作步骤。operation1()和 operation2()是形象办法,须要由子类实现。operation3()是一个可选的钩子办法,能够由子类笼罩。hook()是一个钩子办法,用于管制模板办法中的某些流程。ConcreteClass1 和 ConcreteClass2 是具体子类,实现了形象办法和钩子办法。
模板办法模式在软件开发过程中的场景举例:
- 框架设计
在框架设计中,通常须要定义一些通用的算法流程,并容许用户依据本人的需要定制某些具体的算法步骤。这时,能够应用模板办法模式来定义算法的骨架,将可变的局部留给用户来实现。
- 测试框架
在测试框架中,通常须要执行一系列的测试用例,并对测试后果进行统计和剖析。这时,能够应用模板办法模式来定义测试用例的执行流程,将测试用例的具体实现留给子类来实现。
- 数据库操作
在数据库操作中,通常须要执行一些通用的数据库操作步骤,并容许用户依据本人的需要定制某些具体的操作步骤。这时,能够应用模板办法模式来定义数据库操作的骨架,将可变的局部留给用户来实现。
总之,模板办法模式能够帮忙咱们实现算法的重用和扩大,进步零碎的可维护性和可扩展性。
策略模式
策略模式是一种行为型设计模式,它容许在运行时抉择算法的行为。策略模式定义了一系列算法,将每个算法封装起来,并使它们能够互相替换。抉择哪种算法由客户端决定。
Java 代码示例:
// 定义一个接口
public interface Strategy {int doOperation(int num1, int num2);
}
// 创立实现接口的实体类
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {return num1 + num2;}
}
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {return num1 - num2;}
}
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {return num1 * num2;}
}
// 创立 Context 类
public class Context {
private Strategy strategy;
public Context(Strategy strategy){this.strategy = strategy;}
public int executeStrategy(int num1, int num2){return strategy.doOperation(num1, num2);
}
}
// 应用策略模式
public class StrategyPatternDemo {public static void main(String[] args) {Context context = new Context(new OperationAdd());
System.out.println("10 + 5 =" + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 =" + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 =" + context.executeStrategy(10, 5));
}
}
在软件开发中,策略模式通常利用于以下场景:
- 当须要在运行时抉择算法时,能够应用策略模式。例如,在一个游戏中,玩家能够抉择不同的策略来战败不同的敌人,每个敌人可能有不同的弱点和强点。
- 当须要防止应用大量的条件语句时,能够应用策略模式。例如,在一个电商网站中,能够依据不同的促销策略来计算折扣,而不须要应用大量的 if-else 语句。
- 当须要将算法的实现与应用算法的客户端拆散时,能够应用策略模式。这种形式能够使得算法的实现能够独立于客户端进行批改和扩大,而不会影响客户端的代码。
- 当须要在不同的环境下应用不同的算法时,能够应用策略模式。例如,在一个挪动设施上,能够依据设施的解决能力来抉择不同的算法实现。