前面一篇文章已经提到了设计模式之创建型模式,接下来我们说一说结构型模式
结构型模式
1. 适配器模式
适配器类充当了一个中间层,分为类适配器和对象适配器两种类型。类适配器使用继承来适配对象,而对象适配器使用组合来适配对象。
类适配器
// 目标接口
interface Target {
void request();
}
// 被适配的类
class Adaptee {
void specificRequest() {
System.out.println("Adaptee specificRequest");
}
}
// 类适配器类
class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Target adapter = new ClassAdapter();
adapter.request();
}
}
对象适配器
// 目标接口
interface Target {
void request();
}
// 被适配的类
class Adaptee {
void specificRequest() {
System.out.println("Adaptee specificRequest");
}
}
// 对象适配器类
class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target adapter = new ObjectAdapter(adaptee);
adapter.request();
}
}
2. 桥接模式
在桥接模式中,存在两个独立的继承层次结构:抽象部分和实现部分。抽象部分定义了对象的接口,而实现部分则负责具体的实现。桥接模式通过将抽象部分与实现部分解耦,使得它们可以独立地变化,从而可以灵活地组合不同的抽象部分和实现部分。
// 实现部分接口
interface Implementor {
void operationImpl();
}
// 具体实现类A
class ConcreteImplementorA implements Implementor {
@Override
public void operationImpl() {
System.out.println("ConcreteImplementorA operation");
}
}
// 具体实现类B
class ConcreteImplementorB implements Implementor {
@Override
public void operationImpl() {
System.out.println("ConcreteImplementorB operation");
}
}
// 抽象部分
abstract class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
public abstract void operation();
}
// 扩展抽象部分类
class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
@Override
public void operation() {
System.out.println("RefinedAbstraction operation");
implementor.operationImpl();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Implementor implementorA = new ConcreteImplementorA();
Abstraction abstractionA = new RefinedAbstraction(implementorA);
abstractionA.operation();
Implementor implementorB = new ConcreteImplementorB();
Abstraction abstractionB = new RefinedAbstraction(implementorB);
abstractionB.operation();
}
}
示例中,桥接模式将抽象部分(Abstraction)与实现部分(Implementor)分离,通过组合的方式将抽象部分和实现部分连接起来。这样就可以灵活地扩展和变化抽象部分和实现部分,而不会相互影响。
3. 组合模式
组合模式使得客户端可以统一处理单个对象和对象组合,从而使得组合对象与单个对象具有一致的行为。在组合模式中,有两种主要类型的对象:叶子节点(Leaf)和组合节点(Composite)。叶子节点表示树的最底层节点,它没有子节点,而组合节点可以包含子节点,形成树形结构。
// 组件接口
interface Component {
void operation();
}
// 叶子节点类
class Leaf implements Component {
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void operation() {
System.out.println("Leaf " + name + " operation");
}
}
// 组合节点类
class Composite implements Component {
private List<Component> children = new ArrayList<>();
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
@Override
public void operation() {
for (Component component : children) {
component.operation();
}
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Component leaf1 = new Leaf("A");
Component leaf2 = new Leaf("B");
Component leaf3 = new Leaf("C");
Composite composite = new Composite();
composite.add(leaf1);
composite.add(leaf2);
Composite nestedComposite = new Composite();
nestedComposite.add(leaf3);
composite.add(nestedComposite);
composite.operation();
}
}
示例中,Leaf 表示叶子节点,Composite 表示组合节点。组合节点可以包含叶子节点和其他组合节点,形成树形结构。客户端代码可以统一处理单个对象和对象组合,使用统一的接口对整个树形结构进行操作。组合模式能够更容易地处理嵌套结构,提高了系统的灵活性和可扩展性。
4. 装饰者模式
允许向对象动态地添加额外的功能,而无需修改其原始代码。装饰者模式通过创建一个装饰者类,该类包装原始对象,并在不改变其接口的情况下,扩展其功能。
在装饰者模式中,有四个关键角色:
- 抽象组件(Component):定义了一个抽象接口,可以是一个接口或者抽象类,用于定义装饰者和被装饰者的共同接口。
- 具体组件(Concrete Component):实现了抽象组件接口,是被装饰者的原始对象,可以动态地添加功能。
- 抽象装饰者(Decorator):实现了抽象组件接口,并持有一个指向抽象组件的引用,在其中可以动态地添加额外的功能。
- 具体装饰者(Concrete Decorator):继承自抽象装饰者,实现了具体的装饰逻辑,对原始对象进行装饰。
// 抽象组件
interface Coffee {
String getDescription();
double cost();
}
// 具体组件
class SimpleCoffee implements Coffee {
@Override
public String getDescription() {
return "Simple Coffee";
}
@Override
public double cost() {
return 1.0;
}
}
// 抽象装饰者
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
public String getDescription() {
return decoratedCoffee.getDescription();
}
public double cost() {
return decoratedCoffee.cost();
}
}
// 具体装饰者
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription() + ", Milk";
}
@Override
public double cost() {
return decoratedCoffee.cost() + 0.5;
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getDescription() + " costs $" + coffee.cost());
Coffee milkCoffee = new MilkDecorator(coffee);
System.out.println(milkCoffee.getDescription() + " costs $" + milkCoffee.cost());
}
}
示例中,Coffee 是抽象组件,SimpleCoffee 是具体组件。CoffeeDecorator 是抽象装饰者,MilkDecorator 是具体装饰者。通过装饰者模式,我们可以动态地向原始对象添加额外的功能,而不需要修改原始对象的代码。
5. 外观模式
外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口,用来访问子系统中的一群接口。外观模式隐藏了子系统的复杂性,为客户端提供了一个简单的接口,使得客户端不需要了解子系统的具体实现细节。
外观模式通常包含以下角色:
- 外观(Facade):外观类是客户端访问子系统的入口,它封装了子系统的复杂性,提供了简单的接口供客户端调用。
- 子系统(SubSystem):子系统包含了一组类,实现了子系统的功能。客户端通过外观类与子系统进行交互。
// 子系统类A
class SystemA {
public void operationA() {
System.out.println("SystemA operation");
}
}
// 子系统类B
class SystemB {
public void operationB() {
System.out.println("SystemB operation");
}
}
// 子系统类C
class SystemC {
public void operationC() {
System.out.println("SystemC operation");
}
}
// 外观类
class Facade {
private SystemA systemA;
private SystemB systemB;
private SystemC systemC;
public Facade() {
systemA = new SystemA();
systemB = new SystemB();
systemC = new SystemC();
}
public void operation() {
System.out.println("Facade operation");
systemA.operationA();
systemB.operationB();
.operationC systemC();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Facade facade = new Facade();
facade.operation();
}
}
示例中,外观模式通过外观类 Facade 封装了子系统类 SystemA、SystemB、SystemC 的复杂操作,为客户端提供了一个简单的接口。客户端只需要通过外观类调用 operation 方法,而不需要了解子系统的具体实现细节。外观模式提供了一种简单的方式来访问复杂系统,降低了客户端与子系统之间的耦合度。
6. 享元模式
旨在减少系统中相似对象的数量,从而提高系统的性能和减少内存占用。享元模式通过共享相同的对象实例来减少对象的创建,适用于需要创建大量相似对象的场景。
在享元模式中,有两种关键的角色:
- 享元工厂(Flyweight Factory):负责创建和管理享元对象,通常实现为工厂模式。享元工厂可以维护一个享元池(Flyweight Pool),用于存储共享的享元对象。
- 享元对象(Flyweight):包含内部状态和外部状态,内部状态是可以共享的部分,而外部状态是不可以共享的部分。享元对象通常是不可变的。
import java.util.HashMap;
// 享元工厂
class FlyweightFactory {
private HashMap<String, Flyweight> flyweights = new HashMap<>();
public Flyweight getFlyweight(String key) {
if (flyweights.containsKey(key)) {
return flyweights.get(key);
} else {
Flyweight flyweight = new ConcreteFlyweight(key);
flyweights.put(key, flyweight);
return flyweight;
}
}
}
// 享元接口
interface Flyweight {
void operation();
}
// 具体享元类
class ConcreteFlyweight implements Flyweight {
private String key;
public ConcreteFlyweight(String key) {
this.key = key;
}
@Override
public void operation() {
System.out.println("ConcreteFlyweight " + key + " operation");
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweight1 = factory.getFlyweight("key1");
flyweight1.operation();
Flyweight flyweight2 = factory.getFlyweight("key2");
flyweight2.operation();
Flyweight flyweight3 = factory.getFlyweight("key1");
flyweight3.operation();
}
}
示例中,享元工厂负责创建和管理享元对象,通过享元工厂获取共享的享元对象,避免重复创建相同的对象。具体享元类包含了内部状态(key)和外部状态(operation),通过共享内部状态来减少对象的创建。享元模式可以在需要大量相似对象的场景中节省内存和提高性能。
7. 代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,目的是控制对对象的访问。代理模式可以为其他对象提供一个替代或占位符,以控制对这个对象的访问。
通过代理式模,可以实现对真实主题的访问控制、延迟加载、日志记录等功能。代理模式有助于提高系统的安全性、性能和可维护性。
在代理模式中,有三种主要角色:
- 抽象主题(Subject):定义了代理类和真实主题的共同接口,客户端通过这个接口访问真实主题。
- 真实主题(Real Subject):实现了抽象主题接口,是代理所代表的真实对象。
- 代理(Proxy):包含一个指向真实主题的引用,并且实现了抽象主题接口。代理可以在调用真实主题之前或之后执行额外的操作。
// 抽象主题接口
interface Subject {
void request();
}
// 真实主题类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Processing request");
}
}
// 代理类
class Proxy implements Subject {
private RealSubject realSubject;
public Proxy() {
this.realSubject = new RealSubject();
}
@Override
public void request() {
System.out.println("Proxy: Logging request");
realSubject.request();
System.out.println("Proxy: Post-processing request");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
在}
示例中,Subject
是抽象主题接口,定义了代理类和真实主题类的共同接口。RealSubject
是真实主题类,实现了抽象主题接口,是代理所代表的真实对象。Proxy
是代理类,包含一个指向 RealSubject
的引用,并实了抽现象主题接口。代理类在调用真实主题之前和之后添加了额外的操作。