单例模式
Java的单例模式是一种设计模式,它确保一个类只有一个实例,并提供全局访问点。
单例模式满足三个条件2:
- 构造方法私有化,阻止了外部通过构造方法来再创建实例。
- 自己创建一个静态变量存储实例。
- 对外提供一个静态公有方法获取实例。
在Java中,实现单例模式的方式有很多种,其中最常用的有两种:懒汉式和饿汉式。
懒汉式:
懒汉式单例模式是在需要时才会创建实例,而不是在类加载时创建。这种方式可以减少系统资源的消耗,但是可能会导致线程安全问题。实现方式是在静态变量中保存实例,并添加synchronized关键字确保线程安全。例如:
javapublic class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式:
饿汉式单例模式是在类加载时创建实例,而不是在需要时创建。这种方式可以确保线程安全,但是可能会浪费系统资源。实现方式是在静态变量中创建实例。例如:
javapublic class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
工厂模式
Java的工厂模式是一种创建型设计模式。
工厂模式是一种用于创建对象的模式,它提供了一种方式来将实际创建对象的逻辑封装在工厂类中,而不是直接在客户端代码中创建对象。这样可以将对象的创建与使用分离,提高了系统的灵活性和可维护性。
Java的工厂模式有以下几种形态:
- 简单工厂(Simple Factory)模式:又称静态工厂方法模式(Static Factory Method Pattern)。
- 工厂方法(Factory Method)模式:又称多态性工厂(Polymorphic Factory)模式或虚拟构造子(Virtual Constructor)模式。
- 抽象工厂(Abstract Factory)模式:又称工具箱(Kit 或 Toolkit)模式。
简单工厂模式
Java的简单工厂模式是一种创建型设计模式,它提供了一种创建对象的方式。在Java的简单工厂模式中,通常定义一个静态工厂方法,根据传入的参数不同,返回不同类的实例。
下面是一个Java的简单工厂模式的示例:
java// 定义抽象产品类
public interface Product {
void use();
}
// 定义具体产品类A
public class ProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 定义具体产品类B
public class ProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 定义工厂类
public class Factory {
// 静态工厂方法,根据传入的参数创建不同的产品实例
public static Product createProduct(String type) {
if ("A".equals(type)) {
return new ProductA();
} else if ("B".equals(type)) {
return new ProductB();
} else {
return null;
}
}
}
使用示例:
javapublic class Main {
public static void main(String[] args) {
// 创建产品A的实例
Product productA = Factory.createProduct("A");
productA.use(); // 输出:使用产品A
// 创建产品B的实例
Product productB = Factory.createProduct("B");
productB.use(); // 输出:使用产品B
}
}
在上述示例中,我们定义了一个抽象产品类Product
,以及两个具体产品类ProductA
和ProductB
,它们都实现了Product
接口。然后我们定义了一个工厂类Factory
,其中包含一个静态工厂方法createProduct
,根据传入的参数不同,创建不同的产品实例。最后在Main
类中调用Factory.createProduct
方法创建产品实例并使用。
工厂模式
工厂方法(Factory Method)模式是一种创建型设计模式,它提供了一种创建对象的机制,使得创建对象的具体过程可以在客户端代码中抽象和封装。
在工厂方法模式中,定义一个抽象工厂类,其中包含一个抽象的工厂方法。这个工厂方法由具体的子类实现,每个子类都负责创建一种特定的对象。客户端代码通过调用抽象工厂类的工厂方法来获取所需的对象,而具体的对象创建过程由子类负责实现。
下面是一个简单的Java代码示例,演示了工厂方法模式的实现:
java// 定义抽象产品类
interface Product {
void use();
}
// 实现具体产品类A
class ConcreteProductA implements Product {
@Override
public void use() {
System.out.println("使用具体产品A");
}
}
// 实现具体产品类B
class ConcreteProductB implements Product {
@Override
public void use() {
System.out.println("使用具体产品B");
}
}
// 定义抽象工厂类
abstract class AbstractFactory {
public abstract Product createProduct();
}
// 实现具体工厂类A
class ConcreteFactoryA extends AbstractFactory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 实现具体工厂类B
class ConcreteFactoryB extends AbstractFactory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
AbstractFactory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.use(); // 使用具体产品A
System.out.println();
AbstractFactory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.use(); // 使用具体产品B
}
}
在上述代码中,我们定义了一个抽象产品类Product
,以及两个具体的实现类ConcreteProductA
和ConcreteProductB
。然后,我们定义了一个抽象工厂类AbstractFactory
,其中包含一个抽象的createProduct()
方法。这个方法由具体的子类ConcreteFactoryA
和ConcreteFactoryB
实现,每个子类都负责创建一种具体的Product
对象。最后,在客户端代码中,我们通过调用抽象工厂类的createProduct()
方法来获取所需的产品对象,并使用这些对象进行操作。
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种方式来封装一组具有共同主题的特定工厂,而不需要指定它们的具体类。这样,客户端代码可以通过同一个接口来获取所需的对象,而不需要关心具体的实现。
抽象工厂模式适用于以下情况:
- 一个系统需要一系列相关的对象,而这些对象需要以一种统一的方式创建。
- 一个系统需要使用多个不同但相关的工厂,而每个工厂都创建同一层次结构的不同类型的对象。
抽象工厂模式的主要角色如下:
- 抽象工厂(Abstract Factory):定义创建对象的接口,但由具体的子类来决定要创建的对象。
- 具体工厂(Concrete Factory):实现抽象工厂接口,并创建与该工厂相关的具体对象。
- 抽象产品(Abstract Product):定义产品的公共接口。
- 具体产品(Concrete Product):实现抽象产品的具体类。
下面是一个使用Java实现的抽象工厂模式的示例代码:
java// 抽象工厂接口
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂类A
class ConcreteFactoryA implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ProductAImpl1();
}
@Override
public ProductB createProductB() {
return new ProductBImpl1();
}
}
// 具体工厂类B
class ConcreteFactoryB implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ProductAImpl2();
}
@Override
public ProductB createProductB() {
return new ProductBImpl2();
}
}
// 抽象产品接口
interface ProductA { }
interface ProductB { }
// 具体产品类A1和B1
class ProductAImpl1 implements ProductA { }
class ProductBImpl1 implements ProductB { }
// 具体产品类A2和B2
class ProductAImpl2 implements ProductA { }
class ProductBImpl2 implements ProductB { }
// 客户端代码
public class Client {
public static void main(String[] args) {
AbstractFactory factoryA = new ConcreteFactoryA(); // 创建具体工厂A的对象,返回具体产品A1和B1的实例
ProductA productA1 = factoryA.createProductA(); // 返回具体产品A1的实例
ProductB productB1 = factoryA.createProductB(); // 返回具体产品B1的实例
System.out.println(productA1); // 输出: ProductAImpl1@[hashCode]
System.out.println(productB1); // 输出: ProductBImpl1@[hashCode]
System.out.println();
AbstractFactory factoryB = new ConcreteFactoryB(); // 创建具体工厂B的对象,返回具体产品A2和B2的实例
ProductA productA2 = factoryB.createProductA(); // 返回具体产品A2的实例
ProductB productB2 = factoryB.createProductB(); // 返回具体产品B2的实例
System.out.println(productA2); // 输出: ProductAImpl2@[hashCode]
System.out.println(productB2); // 输出: ProductBImpl2@[hashCode]
}
}
工厂模式(Factory Pattern)和抽象工厂模式(Abstract Factory Pattern)都是创建型设计模式,它们都用于对象的创建,但有一些关键区别:
-
用途:
- 工厂模式:用于创建单一类别的对象,即创建单一类型的产品。它通常包含一个工厂类,该类负责创建具体的产品对象。
- 抽象工厂模式:用于创建一组相关或相互依赖的对象,即创建多个不同类型但相关的产品族。它包含多个工厂类,每个工厂类负责创建一个产品族的对象。
-
对象数量:
- 工厂模式:通常只涉及一个工厂类和一个产品类。
- 抽象工厂模式:涉及多个工厂类和多个产品类,这些产品类通常彼此相关或相互依赖。
-
层次结构:
- 工厂模式:通常没有层次结构,只有一个工厂类和一个产品类。
- 抽象工厂模式:通常具有层次结构,包括一个抽象工厂接口、多个具体工厂类(每个工厂类负责一组相关产品的创建),以及多个相关的产品接口和具体产品类。
-
关系:
- 工厂模式:用于解决对象的创建过程与客户端代码的耦合问题,将对象的创建封装在工厂类中,客户端通过工厂类来创建对象。
- 抽象工厂模式:用于解决一组相关对象的创建问题,它引入了多个工厂类和多个产品类,以便同时创建多个相关产品。
-
示例:
- 工厂模式示例:可以用于创建不同类型的按钮,如Windows按钮和Mac按钮。
- 抽象工厂模式示例:可以用于创建图形用户界面(GUI)中的多个相关组件,如窗口、按钮、文本框等,以确保它们在整个界面中风格一致。
总之,工厂模式和抽象工厂模式都用于对象的创建,但工厂模式更侧重于创建单一类型的对象,而抽象工厂模式用于创建一组相关或相互依赖的对象,通常涉及多个工厂类和多个产品类。选择哪种模式取决于具体的需求和设计目标。
建造者模式
建造者模式(Builder Pattern)是一种创建型设计模式,用于构建一个复杂对象,将对象的构建过程与其表示分离,从而可以使用相同的构建过程创建不同的表示。这种模式适用于需要创建包含大量可选参数的对象。
// 产品类
class Product {
private String part1;
private String part2;
private String part3;
public void setPart1(String part1) {
this.part1 = part1;
}
public void setPart2(String part2) {
this.part2 = part2;
}
public void setPart3(String part3) {
this.part3 = part3;
}
public void show() {
System.out.println("Part 1: " + part1);
System.out.println("Part 2: " + part2);
System.out.println("Part 3: " + part3);
}
}
// 抽象建造者
interface Builder {
void buildPart1(String part1);
void buildPart2(String part2);
void buildPart3(String part3);
Product getResult();
}
// 具体建造者
class ConcreteBuilder implements Builder {
private Product product = new Product();
@Override
public void buildPart1(String part1) {
product.setPart1(part1);
}
@Override
public void buildPart2(String part2) {
product.setPart2(part2);
}
@Override
public void buildPart3(String part3) {
product.setPart3(part3);
}
@Override
public Product getResult() {
return product;
}
}
// 指导者(Director)类,用于构建产品
class Director {
public Product constructProduct(Builder builder) {
builder.buildPart1("Part 1");
builder.buildPart2("Part 2");
builder.buildPart3("Part 3");
return builder.getResult();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director();
Product product = director.constructProduct(builder);
product.show();
}
}
在这个示例中,建造者模式允许我们创建一个Product
对象,该对象具有三个可选部分(part1
,part2
,part3
)。Director
负责指导构建过程,而ConcreteBuilder
负责实际构建Product
对象。客户端代码通过Director
来构建产品,可以根据需要自定义产品的部分。这种方式使得创建复杂对象更加灵活,而不会使构造器变得过于复杂。
生成器模式
生成器模式是一种设计模式,它提供了一种方法来构造一个对象,该对象需要多次创建和初始化。在Java中,可以通过实现Iterator接口来创建一个生成器。
生成器模式的主要特点如下:
- 生成器是一个返回迭代器的对象,该迭代器可以多次访问序列中的元素。
- 生成器具有多个状态,并且只能从上一个状态中移动到下一个状态。
- 生成器使用状态转换方法来改变状态并返回下一个元素。
在Java中,可以通过实现Iterator接口来创建一个生成器。例如,以下代码演示了一个简单的生成器,该生成器生成一系列整数:
javapublic class IntegerGenerator implements Iterator<Integer> {
private int current = 0;
public boolean hasNext() {
return current < Integer.MAX_VALUE;
}
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return current++;
}
}
在这个例子中,IntegerGenerator类实现了Iterator接口,并实现了hasNext()和next()方法。hasNext()方法检查是否还有下一个元素,next()方法返回下一个元素并将当前值增加1。这样,我们可以多次调用next()方法来访问序列中的每个元素。
通过这种方式,生成器模式提供了一种灵活的方法来创建对象,它可以根据需要在多次调用中返回不同的结果。
原型模式
原型模式是一种创建型设计模式,它通过复制(克隆)现有对象来创建新对象,而不是通过使用构造函数来创建。
原型模式在Java中通常使用Clone技术实现,而Java中的复制分为浅复制和深复制。浅复制是通过实现Cloneable接口并覆写其Clone方法实现的,在浅复制的过程中,对象的基本数据类型的变量值会重新被复制和创建,而引用数据类型仍指向原对象的引用。也就是说,浅复制不复制对象的引用类型数据。深复制会复制对象及其所有关联的对象,而浅拷贝只会复制对象本身而不复制关联的对象。
在Web应用中,原型模式会在以下情况使用:
- 类初始化需要消化非常多的资源 。包括数据、硬件资源等。
- 通过new产生一个对象需要非常繁琐的数据准备或访问权限 。
- 构造函数比较复杂 。
- 循环体中生产大量对象 。
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值 。
// 创建一个原型接口
public interface Prototype {
Prototype clone();
}
// 创建一个具体原型类
public class ConcretePrototype implements Prototype {
private String name;
public ConcretePrototype(String name) {
this.name = name;
}
@Override
public ConcretePrototype clone() {
return (ConcretePrototype) super.clone();
}
public String getName() {
return name;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Prototype prototype = new ConcretePrototype("test");
Prototype clonedPrototype = prototype.clone();
System.out.println(clonedPrototype.getName()); // 输出:test
}
}
在这个例子中,我们定义了一个Prototype
接口,该接口包含一个clone()
方法。然后我们创建了一个实现Prototype
接口的ConcretePrototype
类。在ConcretePrototype
类中,我们重写了clone()
方法,并返回一个该类的实例。最后,在客户端代码中,我们创建了一个ConcretePrototype
实例,并使用clone()
方法复制了一个新的实例。
代理模式
代理模式是一种设计模式,提供了一种将类的功能委托给另一个对象的机制。
定义:代理模式是一种结构型设计模式,它提供了一种方式来对一个对象进行包装,从而控制对该对象的访问。
主要作用:代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。
思想:代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
分类:根据代理发生的位置不同,代理可分为静态代理和动态代理。静态代理在程序运行前已经生成代理类,而动态代理在运行时生成代理类。
组成:代理模式通常由被代理对象、代理类、和调用者组成。
// 被代理的接口
interface Subject {
void doSomething();
}
// 被代理的实体类
class RealSubject implements Subject {
public void doSomething() {
System.out.println("RealSubject do something.");
}
}
// 代理类
class ProxySubject implements Subject {
private Subject realSubject;
public ProxySubject() {
realSubject = new RealSubject();
}
public void doSomething() {
System.out.println("ProxySubject do something first.");
realSubject.doSomething();
System.out.println("ProxySubject do something last.");
}
}
// 调用者
class Client {
public static void main(String[] args) {
Subject subject = new ProxySubject();
subject.doSomething();
}
}
运行结果:
csharpProxySubject do something first.
RealSubject do something.
ProxySubject do something last.
在这个例子中,RealSubject
是被代理的实体类,ProxySubject
是代理类。在客户端调用doSomething()
方法时,实际上是调用ProxySubject
的doSomething()
方法。在doSomething()
方法中,先输出"ProxySubject do something first.",然后调用RealSubject
的doSomething()
方法,再输出"ProxySubject do something last."。因此,通过代理类可以控制对实体类的访问,并且可以添加额外的操作。
适配器模式
适配器模式是一种结构型设计模式,用于将一个类的接口转换成用户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高。
类适配器模式:因为Adapter类既继承了Adaptee(被适配类),也实现了Target接口(因为Java不支持多继承,所以这样来实现),所以被称为类适配器。
对象适配器模式:不是使用多继承或继承再实现的方式,而是使用直接关联,或者称为委托的方式。
适配器模式的主要优点有:
- 客户端通过适配器可以透明地调用目标接口。
- 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
- 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
- 在很多业务场景中符合开闭原则。
适配器模式的缺点有:
- 适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性。
- 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。
// 旧的系统类
class OldSystem {
public void oldMethod() {
System.out.println("Old System Method");
}
}
// 新的系统接口
interface NewSystem {
void newMethod();
}
// 适配器类,将OldSystem适配成NewSystem
class Adapter implements NewSystem {
private OldSystem oldSystem;
public Adapter(OldSystem oldSystem) {
this.oldSystem = oldSystem;
}
@Override
public void newMethod() {
oldSystem.oldMethod();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
OldSystem oldSystem = new OldSystem();
NewSystem adapter = new Adapter(oldSystem);
// 使用新的接口调用适配器
adapter.newMethod();
}
}
假设我们有一个旧的类OldSystem
,它有一个名为oldMethod
的方法,但我们想要使用一个新的接口NewSystem
,它有一个名为newMethod
的方法。我们可以创建一个适配器来将OldSystem
适配成NewSystem
,使得客户端可以无缝地使用新的接口。
在这个示例中,我们创建了一个Adapter
类,它实现了NewSystem
接口,并在其内部持有一个OldSystem
的实例。当客户端使用适配器的newMethod
方法时,实际上是调用了OldSystem
的oldMethod
方法,从而实现了旧系统类的适配。这样,客户端可以使用NewSystem
接口而不需要修改旧系统类。
代理模式和适配器模式都是面向对象的编程设计模式,但它们的应用场景和目的不同。
代理模式是通过为某个对象提供一个代理来控制对于该对象的访问。代理类主要负责为委托类(真实对象)预处理消息、过滤消息、传递消息给委托类。代理类本身不负责具体的实现,而是利用委托类来完成具体的业务实现,并将执行结果进行封装处理。
适配器模式是使得其他类的功能接口能够与客户端代码交互,而不需要修改客户端代码。适配器模式通过为不兼容的接口提供了一个适配器,从而使得它们能够协作工作。
总之,代理模式是通过代理类来控制对真实对象的访问,而适配器模式是通过适配器类来使得不兼容的接口能够协作工作。
桥接模式
桥接模式是一种结构型设计模式,它通过将抽象与实现分离,使它们可以独立变化,从而提供系统的灵活性。
桥接模式定义:将抽象与实现分离,使它们可以独立变化。它是一种结构型设计模式,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。
桥接模式主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及他们的功能扩展。它主要优点是实现了抽象和实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开,有助于系统进行分层设计,从而产生更好的结构化系统;缺点是增加系统理解与设计难度,同时由于需要编写太多的类,可能会导致性能损失。
// 定义抽象的接口
interface Image {
void draw();
}
// 实现具体的图像
class Circle implements Image {
public void draw() {
System.out.println("Circle.draw()");
}
}
class Rectangle implements Image {
public void draw() {
System.out.println("Rectangle.draw()");
}
}
// 定义具体绘制类,实现绘制图像的功能
class Drawing {
private Image image;
public Drawing(Image image) {
this.image = image;
}
public void draw() {
image.draw();
}
}
// 使用 Drawing 类进行测试
public class BridgeDemo {
public static void main(String[] args) {
Image circle = new Circle();
Drawing drawing = new Drawing(circle);
drawing.draw();
System.out.println();
Image rectangle = new Rectangle();
drawing = new Drawing(rectangle);
drawing.draw();
}
}
在这个例子中,我们定义了一个抽象的Image
接口和两个实现该接口的具体类Circle
和Rectangle
。然后,我们定义了一个Drawing
类,它包含一个Image
类型的成员变量,并实现了绘制图像的功能。在BridgeDemo
类中,我们创建了Circle
和Rectangle
对象,并将它们传递给Drawing
类的实例,然后调用draw()
方法进行绘制。这样,我们就实现了抽象与实现的分离,使它们可以独立变化。
组合模式
组合模式是一种结构型设计模式,它允许将对象组合成树形结构,以表示部分-整体的层次结构。
组合模式的定义:有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。
组合模式的主要优点有:
- 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码。
- 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”。
组合模式的主要缺点有:
- 设计较复杂,客户端需要花更多时间理清类之间的层次关系。
- 不容易限制容器中的构件。
- 不容易用继承的方法来增加构件的新功能。
// 抽象节点类
class Node {
protected Node left;
protected Node right;
String name;
public Node(String name) {
this.name = name;
}
public void add(Node node, String name) {
if (name.charAt(0) == 'L') {
left = node;
} else {
right = node;
}
}
public void print() {
System.out.println(name);
left.print();
right.print();
}
}
// 叶子节点类
class Leaf extends Node {
public Leaf(String name) {
super(name);
}
@Override
public void print() {
super.print();
}
}
// 测试类
public class Main {
public static void main(String[] args) {
Node root = new Leaf("root");
Node node1 = new Leaf("node1");
Node node2 = new Leaf("node2");
Node leaf3 = new Leaf("leaf3");
Node leaf4 = new Leaf("leaf4");
Node leaf5 = new Leaf("leaf5");
Node leaf6 = new Leaf("leaf6");
root.add(node1, "L1");
root.add(node2, "R1");
node1.add(leaf3, "LL1");
node1.add(leaf4, "LR1");
node2.add(leaf5, "RL1");
node2.add(leaf6, "RR1");
root.print();
}
}
在上述代码中,我们定义了一个抽象节点类Node
和叶子节点类Leaf
。在Node
中,我们定义了左右子节点和节点名称。在Leaf
中,我们继承了Node
类,并重写了print()
方法。在测试类中,我们创建了一个根节点和若干叶子节点,并将它们通过add()
方法组合成一个树形结构。最后,我们调用print()
方法来遍历并打印整个树形结构。
门面模式
门面模式(Facade Pattern)是一种结构型设计模式,它隐藏了系统的复杂性,并向客户端提供一个可以访问系统的接口。这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用1。
门面模式的作用
- 将一些复杂的操作封装起来,以一个简单的接口提供给客户端。
- 可以定义多个子系统,层次之间的粗细粒度需要把握好。一个子系统一个门面类。
门面模式的主要角色
- 门面角色(Facade):这是门面模式的核心。它被客户端角色调用,因此它熟悉子系统的功能。它内部根据客户端角色已有的需求预定了几种功能组合。
- 子系统角色(Subsystem):实现了子系统的功能。对它而言,Facade角色和客户端角色一样是未知的,它没有任何Facade角色的信息和链接。
- 客户端角色(Client):调用Facade角色来完成要得到的功能。
// 客户端角色
class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.methodA();
facade.methodB();
}
}
// 子系统角色
class SubSystemA {
public void methodA() {
System.out.println("执行方法A");
}
}
class SubSystemB {
public void methodB() {
System.out.println("执行方法B");
}
}
// 门面角色
class Facade {
private SubSystemA subSystemA = new SubSystemA();
private SubSystemB subSystemB = new SubSystemB();
public void methodA() {
subSystemA.methodA();
}
public void methodB() {
subSystemB.methodB();
}
}
在这个例子中,客户端角色(Client
)通过门面角色(Facade
)来调用子系统角色(SubSystemA
和SubSystemB
)。Facade
类是门面模式的核心,它封装了子系统的操作,并向客户端提供一个简单的接口。通过将复杂的操作封装在Facade
类中,客户端可以更简单地访问子系统,同时隐藏了子系统的复杂性。
装饰模式
Java装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式给对象动态增加职责。
装饰模式的组成结构
- Component(抽象构件):定义一个抽象接口以规范准备接收附加责任的对象。
- ConcreteComponent(具体构件):实现抽象构件,通过装饰角色为其添加一些职责。
- Decorator(抽象装饰):继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- ConcreteDecorator(具体装饰):实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
装饰模式的重点
装饰模式通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。
// 咖啡接口
interface Coffee {
double getCost();
String getDescription();
}
// 基本咖啡类
class SimpleCoffee implements Coffee {
@Override
public double getCost() {
return 2.0; // 基本咖啡的价格
}
@Override
public String getDescription() {
return "Simple Coffee"; // 基本咖啡的描述
}
}
// 调料装饰器
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
@Override
public double getCost() {
return decoratedCoffee.getCost();
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription();
}
}
// 具体的调料装饰类
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public double getCost() {
return super.getCost() + 1.0; // 牛奶的价格
}
@Override
public String getDescription() {
return super.getDescription() + ", Milk"; // 增加牛奶描述
}
}
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public double getCost() {
return super.getCost() + 0.5; // 糖的价格
}
@Override
public String getDescription() {
return super.getDescription() + ", Sugar"; // 增加糖描述
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Coffee simpleCoffee = new SimpleCoffee();
System.out.println("Cost: " + simpleCoffee.getCost() + ", Description: " + simpleCoffee.getDescription());
Coffee milkCoffee = new MilkDecorator(new SimpleCoffee());
System.out.println("Cost: " + milkCoffee.getCost() + ", Description: " + milkCoffee.getDescription());
Coffee sugarMilkCoffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
System.out.println("Cost: " + sugarMilkCoffee.getCost() + ", Description: " + sugarMilkCoffee.getDescription());
}
}
在这个示例中,我们首先定义了一个Coffee
接口,其中包含getCost
和getDescription
方法。然后,我们创建了一个基本咖啡类SimpleCoffee
,以及两个调料装饰类MilkDecorator
和SugarDecorator
,它们都实现了CoffeeDecorator
抽象类。客户端代码演示了如何创建不同种类的咖啡,并使用装饰器动态添加调料,而不需要修改基本咖啡类的代码。这就是装饰模式的核心思想。
观察者模式
观察者模式
Java的观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都能够得到通知并自动更新。
观察者模式的主要角色有:
- 主题角色(Subject):主题角色保存所有观察者的引用,并通知它们状态发生改变。
- 具体主题角色(Concrete Subject):具体主题角色实现了主题角色,保存了观察者的引用,并在状态发生改变时通知所有观察者。
- 观察者角色(Observer):观察者角色实现了更新方法,该方法在观察的主题的状态发生改变时被调用。
- 具体观察者角色(Concrete Observer):具体观察者角色实现了观察者角色,并在更新方法中定义了如何根据主题状态的改变来更新自身的状态。
下面是一个Java观察者模式的代码例子:
java// 主题角色
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题角色
class ConcreteSubject implements Subject {
private List<Observer> observers;
private int state;
public ConcreteSubject() {
observers = new ArrayList<>();
state = 0;
}
@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(state);
}
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
}
// 观察者角色
interface Observer {
void update(int state);
}
// 具体观察者角色
class ConcreteObserver implements Observer {
private int state;
public ConcreteObserver() {
}
@Override
public void update(int state) {
this.state = state;
System.out.println("Observer received state: " + state);
}
}
客户端代码:
javapublic class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver();
ConcreteObserver observer2 = new ConcreteObserver();
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.setState(10); // 主题状态发生改变,通知所有观察者更新自身状态
}
}
在上述代码中,具体主题角色ConcreteSubject
保存了观察者的引用,并在状态发生改变时通过调用notifyObservers()
方法通知所有观察者。具体观察者角色ConcreteObserver
实现了观察者角色Observer
,并在update()
方法中根据主题状态的改变来更新自身的状态。在客户端代码中,创建了一个具体主题对象ConcreteSubject
和两个具体观察者对象ConcreteObserver
,并将两个观察者对象注册到具体主题对象中。当调用setState()
方法改变具体主题的状态时,具体主题会自动通知所有注册的观察者更新自身的状态。