百练成钢04之设计模式笔记
本文主要参考了刘伟老师的设计模式文章:史上最全设计模式导学目录(完整版)
面向对象设计原则
单一职责原则(Single Responsibility Principle, SRP)
- 一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。
开闭原则(Open-Closed Principle, OCP)
- 一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
- 抽象化是开闭原则的关键。
里氏代换原则(Liskov Substitution Principle, LSP)
- 所有引用基类(父类)的地方必须能透明地使用其子类的对象。
依赖倒转原则(Dependency Inversion Principle, DIP)
- 抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。
- 核心思想是:高层模块不应该依赖于低层模块,而应该依赖于抽象接口。
接口隔离原则(Interface Segregation Principle, ISP)
- 使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
- 核心思想是:客户端不应该依赖于它不需要的接口。也就是说,接口应该被设计得尽可能小、尽可能独立,只包含客户端需要的方法,而不应该包含客户端不需要的方法。这样可以降低类与类之间的耦合度,使得系统更加灵活和易于维护。
合成复用原则(Composite Reuse Principle, CRP)
- 尽量使用对象组合,而不是继承来达到复用的目的。
迪米特法则(Law of Demeter, LoD)
- 一个软件实体应当尽可能少地与其他实体发生相互作用。
创建型模式(Creational Pattern )
创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象。基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式通过以某种方式控制对象的创建来解决问题。创建型模式由两个主导思想构成。一是将系统使用的具体类封装起来,二是隐藏这些具体类的实例创建和结合的方式。
创建型模式又分为对象创建型模式和类创建型模式。对象创建型模式处理对象的创建,类创建型模式处理类的创建。详细地说,对象创建型模式把对象创建的一部分推迟到另一个对象中,而类创建型模式将它对象的创建推迟到子类中。
创建型模式是设计模式中的一种,主要关注对象的创建过程,以实现更加灵活、可扩展和可维护的系统。创建型模式包括以下几种:
- 简单工厂模式(Simple Factory Pattern):由一个工厂对象根据传入的参数决定创建哪一种产品类的实例。
- 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定实例化哪一个类。
- 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。
- 原型模式(Prototype Pattern):通过复制现有的实例来创建新的实例。
- 建造者模式(Builder Pattern):将一个复杂对象的构建过程分解成多个简单的步骤,以便更好地进行控制。
行为型模式(Behavioral Pattern)
在系统运行时,对象之间并不是孤立的,一个对象的运行会影响到其他对象。行为型模式通过划分类和对象的职责,关注系统在运行时对象之间的交互关系。
行为型模式分为类行为型模式和对象行为型模式两种:
- 类行为型模式:类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
- 对象行为型模式:对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。
常见的行为型设计模式包括:
- 观察者模式(Observer Pattern):定义了一种对象间的一对多依赖关系,当一个对象状态改变时,它的所有依赖对象都会收到通知并自动更新。
- 命令模式(Command Pattern):将请求封装为一个对象,从而使得请求的操作和执行操作的对象分离开来,使得请求可以灵活的被执行。
- 策略模式(Strategy Pattern):定义了一系列算法,将每个算法都封装起来,并且使它们可以相互替换,从而使得算法可以独立于客户端而变化。
- 模板方法模式(Template Method Pattern):定义一个操作中的算法框架,将一些步骤延迟到子类中,从而使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤。
- 迭代器模式(Iterator Pattern):提供一种顺序访问一个聚合对象中各个元素的方法,而又不暴露该对象的内部表示。
- 责任链模式(Chain of Responsibility Pattern):使得多个对象都有机会处理请求,从而避免了请求发送者和接收者之间的耦合关系,将请求的发送和处理解耦。
- 状态模式(State Pattern):将一个对象的行为与它的状态分离开来,从而使得同一个状态下,对象的行为可以有不同的变化,而不会出现过多的分支语句。
结构型模式(Structural Pattern)
这些设计模式关注类和对象的组合,结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承来组织接口和类,后者釆用关联来组合对象
由于组合关系或聚合关系比较继承关系耦合度低,满足“合成复合原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。
结构型有以下几种模式:
- 适配器模式:用于将一个类的接口转换成另外一个接口,以满足客户端的需求。在实际应用中,我们可能需要使用一个已存在的类,但是它的接口与我们的需求不匹配,这时我们就可以使用适配器模式。适配器模式分为类适配器模式和对象适配器模式。
- 桥接模式:用于将抽象部分和实现部分分离,使它们可以独立地变化。它通过将一个抽象类和它的实现类分离开来,使它们可以独立地变化和扩展。桥接模式的核心思想是“组合优于继承”,它可以有效地减少类的继承关系,降低系统的耦合度。
- 装饰器模式:用于动态地给对象添加一些额外的职责,而不需要修改原有的类。它通过使用一个装饰器类来包装原有的类,从而在运行时动态地扩展类的功能。装饰器模式可以有效地解决类的继承关系过于复杂的问题。
- 组合模式:用于将对象组合成树形结构来表示“部分-整体”的层次结构,使得客户端可以统一地处理单个对象和组合对象。组合模式分为透明式组合模式和安全式组合模式。
- 外观模式:用于为一组复杂的子系统提供一个简单的接口,使得外部程序可以更容易地使用这些子系统。外观模式通过提供一个高层次的接口,将子系统的复杂性隐藏起来,使得客户端可以更加方便地使用子系统。
- 享元模式:通过共享已经存在的对象来减少系统中对象的数量,从而降低系统的内存占用和提高系统的性能。它适用于系统中存在大量的相似对象,并且这些对象的状态可以被外部对象共享的情况。
- 代理模式:用于为其他对象提供一种代理以控制对这个对象的访问。代理模式在不改变原有对象的基础上,提供了一种间接访问对象的方式,从而可以在不改变原有对象的情况下实现一些额外的功能。代理模式分为静态代理和动态代理两种。
设计模式
简单工厂模式(Simple Factory Pattern)
一种创建型设计模式,它提供了一个通用的接口来创建不同类型的对象,而无需暴露它们的创建逻辑。简单工厂模式通过将对象的创建委托给一个单独的工厂类来实现,从而使代码更加灵活和可维护。
在简单工厂模式中,客户端不直接实例化对象,而是通过向工厂类发送请求来获得所需的对象。工厂类根据客户端的请求,返回相应的对象实例。这种方法可以帮助客户端与具体类之间解耦,并提供一种简单的方法来创建对象。
简单工厂模式通常涉及三种角色:
- 工厂类(Factory):负责创建具体的产品对象。
- 抽象产品类(Product):定义产品的接口,由具体的产品类实现。
- 具体产品类(ConcreteProduct):实现抽象产品类的接口,由工厂类创建。
使用简单工厂模式,客户端只需要知道所需产品的类型即可,无需知道其具体实现。这种方法可以大大简化客户端的代码,并且使代码更加易于扩展和维护。
代码示例
/**
* 简单工厂模式(Simple Factory Pattern):定义一个工厂类,
* 它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
* 因为在简单工厂模式中用于创建实例的方法是静态(static)方法,
* 因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,
* 它属于类创建型模式。
*
* 引入新的产品,需要修改工厂类来进行创建产品,违反开闭原则
*/
public class SimpleFactoryTest {
public static void main(String[] args) {
Product a = ProductFactory.create("a");
a.method();
Product b = ProductFactory.create("b");
b.method();
}
}
abstract class Product{
public abstract void method();
}
class ProductA extends Product{
public ProductA(){
}
public void method(){
System.out.println("ProductA方法执行了");
}
}
class ProductB extends Product{
public ProductB(){
}
public void method(){
System.out.println("ProductB方法执行了");
}
}
class ProductFactory{
public static Product create(String productName){
if ("a".equals(productName)) {
return new ProductA();
}else if ("b".equals(productName)){
return new ProductB();
}else{
return null;
}
}
}
工厂方法模式(Factory Method Pattern)
一种创建型设计模式,它提供了一种将对象创建的过程封装在子类中的方式。在工厂方法模式中,将创建对象的代码移到子类中,而不是在父类中直接创建对象。
在工厂方法模式中,定义一个抽象的工厂接口(Factory),用于创建对象。然后,具体的工厂(Concrete Factory)实现该接口,并负责创建具体的对象。由于每个具体的工厂都实现了相同的工厂接口,因此客户端代码可以使用抽象工厂接口来创建对象,而无需了解具体的实现细节。
工厂方法模式的核心思想是将对象的创建从客户端代码中分离出来,使得客户端代码不需要了解对象的具体实现方式。这样可以提高代码的可维护性和可扩展性,因为如果需要新增一种对象类型,只需要添加一个新的具体工厂类即可,不需要修改客户端代码。
工厂方法模式是一种非常常见的设计模式,被广泛应用于各种编程语言和应用场景中,例如Java中的JDBC API就使用了工厂方法模式来创建数据库连接对象。
在工厂方法模式结构图中包含如下几个角色:
● Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。
● ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。
● Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。
● ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。
代码示例
/**
* 工厂方法模式(Factory Method Pattern):
* 定义一个用于创建对象的接口,
* 让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
* 工厂方法模式又简称为工厂模式(Factory Pattern),
* 又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。
* 工厂方法模式是一种类创建型模式。
*
* 进行单一职责划分,每个工厂负责设计自己的汽车产品
*/
public class FactoryMethodTest {
public static void main(String[] args) {
Factory carriageFactory = new CarriageFactory();
Vehicle carriage = carriageFactory.createVehicle();
carriage.sayHello();
Factory busFactory = new BusFactory();
Vehicle bus = busFactory.createVehicle();
bus.sayHello();
}
}
abstract class Factory{
public abstract Vehicle createVehicle();
}
// 产品:车
abstract class Vehicle{
public abstract void sayHello();
}
// 轿车
class Carriage extends Vehicle{
public Carriage(){}
@Override
public void sayHello() {
System.out.println("Hello,我是一辆轿车");
}
}
// 公交车
class Bus extends Vehicle{
public Bus(){}
@Override
public void sayHello() {
System.out.println("Hello,我是一辆公交车");
}
}
// 轿车工厂:负责生产轿车
class CarriageFactory extends Factory{
@Override
public Vehicle createVehicle() {
return new Carriage();
}
}
// 公交车工厂:负责生产公交车
class BusFactory extends Factory{
@Override
public Vehicle createVehicle() {
return new Bus();
}
}
抽象工厂模式(Abstract Factory Pattern )
一种创建型设计模式,它提供了一种方法,通过定义一个接口来创建一组相关或依赖对象的系列,而不需要指定其具体类。抽象工厂模式是工厂方法模式的扩展,它使用多个工厂来创建一组相关的对象。
在抽象工厂模式中,有一个抽象工厂类,它定义了一组工厂方法来创建一组相关的对象。具体的工厂类实现这些工厂方法来创建具体的对象。每个具体工厂类都实现了抽象工厂类中定义的一组工厂方法。
抽象工厂模式的优点是可以使客户端代码从具体的产品类中解耦出来,因为客户端只需要知道抽象工厂和抽象产品的接口,而不需要知道具体的工厂和产品类。这样就可以方便地替换产品系列,而不会影响客户端代码。同时,抽象工厂模式也符合开闭原则,因为可以方便地添加新的产品系列,而不需要修改已有的代码。
在抽象工厂模式结构图中包含如下几个角色:
- AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
- ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
- AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
- ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
代码示例
/**
* 工厂方法模式(Factory Method Pattern):
* 定义一个用于创建对象的接口,
* 让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
* 工厂方法模式又简称为工厂模式(Factory Pattern),
* 又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。
* 工厂方法模式是一种类创建型模式。
*
* 进行单一职责划分,每个工厂负责设计自己的汽车产品
*/
public class FactoryMethodTest {
public static void main(String[] args) {
Factory carriageFactory = new CarriageFactory();
Vehicle carriage = carriageFactory.createVehicle();
carriage.sayHello();
Factory busFactory = new BusFactory();
Vehicle bus = busFactory.createVehicle();
bus.sayHello();
}
}
abstract class Factory{
public abstract Vehicle createVehicle();
}
// 产品:车
abstract class Vehicle{
public abstract void sayHello();
}
// 轿车
class Carriage extends Vehicle{
public Carriage(){}
@Override
public void sayHello() {
System.out.println("Hello,我是一辆轿车");
}
}
// 公交车
class Bus extends Vehicle{
public Bus(){}
@Override
public void sayHello() {
System.out.println("Hello,我是一辆公交车");
}
}
// 轿车工厂:负责生产轿车
class CarriageFactory extends Factory{
@Override
public Vehicle createVehicle() {
return new Carriage();
}
}
// 公交车工厂:负责生产公交车
class BusFactory extends Factory{
@Override
public Vehicle createVehicle() {
return new Bus();
}
}
单例模式(Singleton Pattern)
单例模式是结构最简单的设计模式一,在它的核心结构中只包含一个被称为单例类的特殊类。
单例模式有三个要点:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
单例模式结构图中只包含一个单例角色:
● Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
饿汉式与懒汉式
- 饿汉式:是指在类加载的时候就创建了单例对象,因此也被称为静态单例模式。它的实现非常简单,在类中声明一个静态的、final的实例,然后提供一个静态的、公共的方法来访问该实例。因为在类加载的时候就创建了单例对象,所以在多线程环境下也是线程安全的,不需要考虑同步问题。但是,这种方式的缺点是无法进行延迟加载,如果单例对象比较大或者创建它的代价比较大,就会影响系统的性能。
- 懒汉式:是指在第一次使用时才创建单例对象,因此也被称为动态单例模式。懒汉式的实现方式有很多种,最常见的是使用双重检查锁定(double-checked locking)来保证线程安全和延迟加载。在双重检查锁定中,先检查单例对象是否已经被创建了,如果没有,则加锁,再次检查单例对象是否已经被创建了,如果还没有,就创建一个单例对象。这种方式的优点是延迟加载,可以在需要时才创建单例对象,减少了系统开销,但是需要考虑线程安全问题,因为在多线程环境下,可能会出现多个线程同时访问到未创建的单例对象,需要进行同步处理,否则可能会创建多个实例。
- 总的来说,饿汉式是线程安全、简单易用,但不支持延迟加载;懒汉式支持延迟加载,但需要考虑线程安全问题。在实际开发中,根据具体的情况选择使用哪种方式实现单例模式。
代码示例
public class SingletonTest{
public static void main(String[] args) throws InterruptedException {
Singleton1 singleton11 = Singleton1.getInstance();
Singleton1 singleton12 = Singleton1.getInstance();
System.out.println("打印Singleton1类实例:singleton11"+singleton11);
System.out.println("打印Singleton1类实例:singleton12"+singleton12);
System.out.println("=========================================================");
Singleton2 instance21 = Singleton2.getInstance();
Singleton2 instance22 = Singleton2.getInstance();
System.out.println("打印Singleton2类实例:instance21"+instance21);
System.out.println("打印Singleton2类实例:instance22"+instance22);
System.out.println("=========================================================");
Singleton3 instance31 = Singleton3.getInstance();
Singleton3 instance32 = Singleton3.getInstance();
System.out.println("打印Singleton3类实例:instance31"+instance31);
System.out.println("打印Singleton3类实例:instance32"+instance32);
System.out.println("=========================================================");
Singleton4 instance41 = Singleton4.SingletonEnum.SINGLETON.getInstance();
Singleton4 instance42 = Singleton4.SingletonEnum.SINGLETON.getInstance();
System.out.println("打印Singleton4类实例:instance41"+instance41);
System.out.println("打印Singleton4类实例:instance42"+instance42);
System.out.println("=========================================================");
Thread.sleep(10000);
}
}
/**
* 单例模式:类只有私有构造方法
* 懒汉式:当类被加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。
* 方式一:饿汉式创建:创建出来的类可能不被使用,造成资源浪费
*/
class Singleton1 {
public static String test="TEST";
private static Singleton1 singleton = new Singleton1();
private Singleton1(){
System.out.println("类已被创建");
}
public static Singleton1 getInstance(){
return singleton;
}
}
/**
* 方式二:懒汉式创建:静态内部类创建
* 实现思路:将单列的实例放在一个静态内部类中,
* 在第一次调用单例对象时再进行创建,
* 这种方式即能保证线程安全,又能保证单例对象延迟加载
*/
class Singleton2 {
private Singleton2(){}
private static class Singleton2Inner{
private static final Singleton2 INSTANCE = new Singleton2();
}
public static Singleton2 getInstance(){
return Singleton2Inner.INSTANCE;
}
}
/**
* 方式三:双重检测机制+volatile(防止java虚拟机进行指令重排)
* 懒汉式单例类在第一次使用时创建,
* 无须一直占用系统资源,
* 实现了延迟加载,
* 但是必须处理好多个线程同时访问的问题,
* 特别是当单例类作为资源控制器,
* 在实例化时必然涉及资源初始化,
* 而资源初始化很有可能耗费大量时间,
* 这意味着出现多线程同时首次引用此类的机率变得较大,
* 需要通过双重检查锁定等机制进行控制,
* 这将导致系统性能受到一定影响。
*/
class Singleton3 {
private Singleton3(){ }
public volatile static Singleton3 singleton3;
public static Singleton3 getInstance(){
if (singleton3 == null){
synchronized (Singleton3.class){
if (singleton3 == null){
return new Singleton3();
}
}
}
return singleton3;
}
}
/**
* 方式四:使用枚举,防止反射,客户端克隆使得单例对象不唯一
*/
class Singleton4{
private Singleton4(){}
public static enum SingletonEnum{
SINGLETON;
private Singleton4 instance = null;
private SingletonEnum(){
instance = new Singleton4();
}
public Singleton4 getInstance(){
return instance;
}
}
}
原型模式(Prototype Pattern)
一种创建型设计模式,其核心思想是通过复制现有对象来创建新的对象,而无需使用显式的构造函数或工厂方法。在原型模式中,我们首先创建一个原型对象,然后使用该对象创建新的对象。新的对象是通过将原型对象的属性和方法复制到新对象中来创建的,这样可以避免昂贵的对象创建过程。
使用原型模式的优点是:
- 提高了对象的创建效率;
- 简化了对象创建过程;
- 可以在运行时动态添加和删除对象。
一个例子就是,如果你有一个复杂的对象,想要创建它的多个实例,而每个实例的属性和方法略有不同,那么使用原型模式可以快速创建这些对象,而无需逐个定义每个对象的构造函数。
原型模式是一种“另类”的创建型模式,创建克隆对象的工厂就是原型类自身,工厂方法由克隆方法来实现。
注意:克隆分为浅克隆、深克隆。
浅拷贝(浅克隆)是一种复制方式,它只复制了对象的指针或引用,而不是对象本身。这意味着复制后的对象与原始对象共享相同的内存空间。因此,如果修改了复制后的对象,原始对象也会受到影响。
深拷贝(深克隆)是一种更彻底的复制方式,它不仅复制了对象的指针或引用,还会递归复制对象中包含的所有数据。这意味着复制后的对象是完全独立的,对其进行的任何修改都不会影响原始对象。
在原型模式结构图中包含如下几个角色:
- Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。
- ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
- Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。
代码示例
/**
* 原型模式(Prototype Pattern):
* 一种创建型设计模式,其核心思想是通过复制现有对象来创建新的对象
*/
public class PrototypeTest extends Prototype {
public static void main(String[] args) throws CloneNotSupportedException {
ConcretePrototype concretePrototype = new ConcretePrototype();
Content content = new Content();
content.setData("数据内容");
concretePrototype.setContent(content);
ConcretePrototype cloneConcretePrototype = (ConcretePrototype)concretePrototype.clone();
System.out.println("克隆前原型:"+concretePrototype);
System.out.println("克隆后原型:"+cloneConcretePrototype);
System.out.println("-----------------------------------");
System.out.println("克隆前原型中content:"+concretePrototype.getContent());
System.out.println("克隆前原型中content:"+cloneConcretePrototype.getContent());
System.out.println("使用原型管理器进行数据克隆:"+PrototypeManager.getPrototypeManager().getContent(concretePrototype.getContent().getClass()));
//默认是浅拷贝,要实现对内容的数据深拷贝,则需要内容对象实现Cloneable接口,同时在克隆原型类对象时进行对内容对象进行处理
}
}
// 抽象原型类
abstract class Prototype implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Content implements Cloneable{
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 具体原型类
class ConcretePrototype extends Prototype{
private String name;
private Content content;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Content getContent() {
return content;
}
public void setContent(Content content) {
this.content = content;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();// 使用object的克隆,默认是浅克隆
}
}
class PrototypeManager{
private Hashtable ht = new Hashtable();
private static PrototypeManager prototypeManager = new PrototypeManager();
public static PrototypeManager getPrototypeManager(){
return prototypeManager;
}
//
public Content getContent(Class<?> contentClass){
try{
if(!ht.containsKey(contentClass)){
Content content = (Content)contentClass.newInstance();
ht.put(contentClass,content);
return (Content)content.clone();
}else {
return (Content) ((Content)ht.get(contentClass)).clone();
}
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
建造者模式(Builder Pattern)
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
在建造者模式结构图中包含如下几个角色:
-
Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
-
ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
-
Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
-
Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
代码示例
/**
* 建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
*
* ● Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
* ●ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
* ●Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
* ● Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
*/
public class BuilderTest {
public static void main(String[] args) {
Director director = new Director(new ConcreteRoleBuilder());
Role role = director.construct("松江", "23", "男");
System.out.println(role);
}
}
/**
* 可以理解玩家要创建一个角色,但是作为我玩家来说,玩家不知道如何创建,玩家只能告诉具体的建造者(游戏设计师),根据我们的想法构建一个角色的实例。
* 玩家就是指挥者,游戏设计师就是具体建造者
* 不同游戏师有不同的设计方式,玩家只能依赖游戏设计师设计方式来 创建一个具体的角色
* 此处玩家决定角色的构建顺序,以及告诉设计师角色最终的形态,而设计师负责进行构建角色
*
*/
abstract class RoleBuilder{
protected Role role = new Role();
public abstract void setRoleName(String name);
public abstract void setRoleAge(String age);
public abstract void setRoleSex(String sex);
public abstract Role getRole();
}
class Role{
private String name;
private String age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Role{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
class ConcreteRoleBuilder extends RoleBuilder{
@Override
public void setRoleName(String name) { this.role.setName(name);
System.out.println("正在构建名字");}
@Override
public void setRoleAge(String age) { this.role.setAge(age);
System.out.println("正在构建年龄");}
@Override
public void setRoleSex(String sex) { this.role.setSex(sex);
System.out.println("正在构建性别");}
@Override
public Role getRole() {
return this.role;
}
}
class Director{
private RoleBuilder roleBuilder;
public Director(RoleBuilder roleBuilder){
this.roleBuilder = roleBuilder;
}
public Role construct(String name,String age,String sex){
roleBuilder.setRoleName(name);
roleBuilder.setRoleAge(age);
roleBuilder.setRoleSex(sex);
return roleBuilder.getRole();
}
}
适配器模式(Adapter Pattern)
它可以将一个类的接口转换成客户端所期望的另一个接口。在适配器模式中,适配器作为一个中间层,将不兼容的接口转换为兼容的接口,从而让不同的对象能够协同工作。
在对象适配器模式结构图中包含如下几个角色:
● Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
● Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
● Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
适配器模式类型
- 类适配器(Class Adapter):类适配器通过继承被适配的类来实现适配器功能。在适配器类中,通过调用被适配类的方法,来实现适配器类的接口。这种方式需要对被适配类进行修改,因此需要谨慎使用。
- 对象适配器(Object Adapter):对象适配器通过组合被适配类的实例来实现适配器功能。在适配器类中,通过调用被适配类实例的方法,来实现适配器类的接口。这种方式不需要对被适配类进行修改,因此更加灵活。
- 接口适配器(Interface Adapter):接口适配器通过定义一个抽象适配器类来实现适配器功能。在适配器类中,提供了一组默认的空方法,让子类只需要实现自己需要的方法即可。这种方式可以有效地避免了对被适配类的依赖,同时也提供了更加灵活的扩展方式。
代码示例
类适配器(Class Adapter)
/**
* 类适配器,通过继承来进行适配,而JAVA是单继承,所以一旦继承了被适配者类,目标类就需要为接口,来进行实现
* 而类与类之间一旦存在继承关系,则耦合性较高
*/
public class ClassAdapterTest {
public static void main(String[] args) {
Phone phone = new Phone();
// 提供一个电源适配器来供给手机充电
phone.charging(new PhoneVoltageAdapter());
}
}
/**
* 适配器模式(Adapter Pattern):
* 将一个接口转换成客户希望的另一个接口,
* 使接口不兼容的那些类可以一起工作,
* 其别名为包装器(Wrapper)。
* 适配器模式既可以作为类结构型模式,
* 也可以作为对象结构型模式。
* 注:在适配器模式定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。
*
* 根据适配器类与适配者类的关系不同,
* 适配器模式可分为对象适配器和类适配器两种,
* 在对象适配器模式中,
* 适配器与适配者之间是关联关系;
* 在类适配器模式中,适配器与适配者之间是继承(或实现)关系。
*
* 比如电源适配器可作为适配器模式的典型讲解
* 家用电压220V,而手机只能支持5V,两者不能直连,所以引入电源适配器进行两者适配,电源适配器将家用220V转成可供手机充电的电压5V,从而实现可以手机充电。
*
*/
/**
* 家用电压220V
*/
class HouseholdVoltage{
public int getHouseholdVoltage(){
System.out.println("获得家用电压220V---------------");
return 220;
}
}
/**
* 手机电压5V
*/
interface IPhoneVoltage5V{
public int getVoltage5V();
}
/**
*
*/
class PhoneVoltageAdapter extends HouseholdVoltage implements IPhoneVoltage5V{
@Override
public int getVoltage5V() {
int householdVoltage = this.getHouseholdVoltage();
System.out.println("将家用电源按照一定的方式转换,获得电压5V--------------------");
return householdVoltage/44;
}
}
/**
* 手机充电
*/
class Phone{
// 充电
public void charging(IPhoneVoltage5V adapter){
int voltage5V = adapter.getVoltage5V();
if (voltage5V==5){
System.out.println("电源适配器在转换后获得电压5V,可以进行充电--------------------------");
}
};
}
对象适配器(Object Adapter)
/**
* 将适配器和被适配者改为聚合,即引用适配器
* 对象适配器模式
* -- 在这种适配器模式中,适配器容纳一个它包裹的类的实例
*/
public class ObjectAdapterTest {
public static void main(String[] args) {
Phone phone = new Phone();
phone.charging(new PhoneVoltageAdapter(new HouseholdVoltage()));
}
}
/**
* 家用电压220V
*/
class HouseholdVoltage{
public int getHouseholdVoltage(){
System.out.println("获得家用电压220V---------------");
return 220;
}
}
/**
* 手机电压5V
*/
interface IPhoneVoltage5V{
public int getVoltage5V();
}
/**
* 适配器
* 通过聚合的关系来实现适配器,作为对象适配器
*/
class PhoneVoltageAdapter implements IPhoneVoltage5V {
private HouseholdVoltage householdVoltage;
public PhoneVoltageAdapter(HouseholdVoltage householdVoltage){
this.householdVoltage = householdVoltage;
}
@Override
public int getVoltage5V() {
int householdVoltage = this.householdVoltage.getHouseholdVoltage();
System.out.println("将家用电源按照一定的方式转换,获得电压5V--------------------");
return householdVoltage/44;
}
}
/**
* 手机充电
*/
class Phone{
// 充电
public void charging(IPhoneVoltage5V adapter){
int voltage5V = adapter.getVoltage5V();
if (voltage5V==5){
System.out.println("电源适配器在转换后获得电压5V,可以进行充电--------------------------");
}
};
}
接口适配器(Interface Adapter)
/**
* 接口适配器:将接口的多个方法进行隔离,使得子类不需要将全部进行方法重写实现
*/
public class InterfaceAdapterTest {
public static void main(String[] args) {
InterfaceAdapterImpl interfaceAdapter = new InterfaceAdapterImpl();
interfaceAdapter.method3();
}
}
interface IInterface{
public void method1();
public void method2();
public void method3();
}
/**
* 直接继承接口类,则需要对方法全部进行重写
*/
class InterfaceSubClass implements IInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
@Override
public void method3() {
}
}
// 引入抽象类,来对接口方法进行默认实现
abstract class InterfaceAdapter implements IInterface{
@Override
public void method1() {
System.out.println("默认实现1----------------");
}
@Override
public void method2() {
System.out.println("默认实现2----------------");
}
@Override
public void method3() {
System.out.println("默认实现3----------------");
}
}
class InterfaceAdapterImpl extends InterfaceAdapter{
@Override
public void method3() {
System.out.println("选择适配方法3--------------------");
}
}
桥接模式(Bridge Pattern)
将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
在桥接模式结构图中包含如下几个角色:
- Abstraction(抽象类):用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,它既可以包含抽象业务方法,也可以包含具体业务方法。
- RefinedAbstraction(扩充抽象类):扩充由Abstraction定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中可以调用在Implementor中定义的业务方法。
- Implementor(实现类接口):定义实现类的接口,这个接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor接口仅提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,在Abstraction中不仅拥有自己的方法,还可以调用到Implementor中定义的方法,使用关联关系来替代继承关系。
- ConcreteImplementor(具体实现类):具体实现Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplementor对象将替换其父类对象,提供给抽象类具体的业务操作方法。
代码示例
/**
* 建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
*
* ● Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
* ●ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
* ●Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
* ● Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
*/
public class BuilderTest {
public static void main(String[] args) {
Director director = new Director(new ConcreteRoleBuilder());
Role role = director.construct("松江", "23", "男");
System.out.println(role);
}
}
/**
* 可以理解玩家要创建一个角色,但是作为我玩家来说,玩家不知道如何创建,玩家只能告诉具体的建造者(游戏设计师),根据我们的想法构建一个角色的实例。
* 玩家就是指挥者,游戏设计师就是具体建造者
* 不同游戏师有不同的设计方式,玩家只能依赖游戏设计师设计方式来 创建一个具体的角色
* 此处玩家决定角色的构建顺序,以及告诉设计师角色最终的形态,而设计师负责进行构建角色
*
*/
abstract class RoleBuilder{
protected Role role = new Role();
public abstract void setRoleName(String name);
public abstract void setRoleAge(String age);
public abstract void setRoleSex(String sex);
public abstract Role getRole();
}
class Role{
private String name;
private String age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Role{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", sex='" + sex + '\'' +
'}';
}
}
class ConcreteRoleBuilder extends RoleBuilder{
@Override
public void setRoleName(String name) { this.role.setName(name);
System.out.println("正在构建名字");}
@Override
public void setRoleAge(String age) { this.role.setAge(age);
System.out.println("正在构建年龄");}
@Override
public void setRoleSex(String sex) { this.role.setSex(sex);
System.out.println("正在构建性别");}
@Override
public Role getRole() {
return this.role;
}
}
class Director{
private RoleBuilder roleBuilder;
public Director(RoleBuilder roleBuilder){
this.roleBuilder = roleBuilder;
}
public Role construct(String name,String age,String sex){
roleBuilder.setRoleName(name);
roleBuilder.setRoleAge(age);
roleBuilder.setRoleSex(sex);
return roleBuilder.getRole();
}
}
组合模式(Composite Pattern)
组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。
在组合模式中,有两种基本类型的对象:叶子对象和组合对象。叶子对象是不能再被分解的基本单元,而组合对象由多个叶子对象或组合对象组成。这些对象组合形成了一个树形结构,根节点是一个组合对象,子节点可以是组合对象或叶子对象。
组合模式提供了一个一致的方式来处理树形结构中的所有对象。它通过统一处理叶子对象和组合对象来简化了客户端的代码,使得客户端可以像处理单个对象一样处理组合对象和叶子对象。同时,组合模式也保证了树形结构中的所有对象都可以被遍历到,无论是组合对象还是叶子对象。
组合模式通常使用递归的方式遍历树形结构,从而实现对所有对象的操作。在使用组合模式时,需要注意组合对象和叶子对象之间的区别,以及如何遍历整个树形结构。
组合模式具有以下两种模式
- 透明组合模式:是指将组合中的所有对象都视为具有相同的接口和属性,即叶子节点和容器节点都实现了相同的接口,使得客户端无需关心对象的具体类型,可以一致地对待叶子节点和容器节点。这种模式的好处是简化了客户端的代码,但是可能会带来安全性问题,因为客户端可以在不知情的情况下调用不适用于叶子节点的方法,导致程序出错。
- 安全组合模式:是指将组合中的叶子节点和容器节点分别实现不同的接口,叶子节点只实现基本操作,而容器节点还可以进行添加、删除、查找等操作。这种模式的好处是安全性更高,因为客户端只能调用适用于容器节点的方法,但是客户端的代码可能会变得更加复杂。
在组合模式结构图中包含如下几个角色:
- Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。
- Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。
- Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。
代码示例
安全组合模式
/**
* 安全组合模式
* 是指将组合中的叶子节点和容器节点分别实现不同的接口,叶子节点只实现基本操作,而容器节点还可以进行添加、删除、查找等操作。这种模式的好处是安全性更高,因为客户端只能调用适用于容器节点的方法,但是客户端的代码可能会变得更加复杂。
* 不能完全面对抽象编程
*/
public class SecurityCompositePatternTest {
public static void main(String[] args) {
FolderSecurityComponent securityComponent= new FolderSecurityComponent("容器");
FolderSecurityComponent folderSecurityComponent1=new FolderSecurityComponent("文件夹一");
FolderSecurityComponent folderSecurityComponent2 = new FolderSecurityComponent("文件夹二");
FolderSecurityComponent folderSecurityComponent3 = new FolderSecurityComponent("文件夹三");
FolderSecurityComponent folderSecurityComponent4 = new FolderSecurityComponent("文件夹四");
securityComponent.addComponent(folderSecurityComponent4);
folderSecurityComponent4.addComponent(folderSecurityComponent1);
folderSecurityComponent4.addComponent(folderSecurityComponent2);
folderSecurityComponent4.addComponent(folderSecurityComponent3);
SecurityComponent folderComponent = new DocFileSecurityComponent("doc文件1");
SecurityComponent videoFileComponent = new VideoFileSecurityComponent("视频文件1");
SecurityComponent textFileComponent = new TextFileSecurityComponent("文本文件1");
securityComponent.addComponent(textFileComponent);
folderSecurityComponent1.addComponent(folderComponent);
folderSecurityComponent1.addComponent(videoFileComponent);
folderSecurityComponent1.addComponent(textFileComponent);
folderSecurityComponent2.addComponent(videoFileComponent);
folderSecurityComponent3.addComponent(videoFileComponent);
securityComponent.operation();
}
}
abstract class SecurityComponent {
public String componentName;
protected List<SecurityComponent> componentList;
public SecurityComponent(String componentName){
this.componentName=componentName;
this.componentList=new ArrayList<>();
}
public abstract void operation();
}
/**
* 创建一个文件夹类
*/
class FolderSecurityComponent extends SecurityComponent{
public FolderSecurityComponent(String componentName) {
super(componentName);
}
public void addComponent(SecurityComponent securityComponent){
this.componentList.add(securityComponent);
}
public void removeComponent(SecurityComponent securityComponent){
this.componentList.remove(securityComponent);
}
public SecurityComponent getComponent(int index){
return this.componentList.get(index);
}
@Override
public void operation() {
System.out.println("打开文件夹["+this.componentName+"]----------------------");
for (SecurityComponent securityComponent : this.componentList) {
securityComponent.operation();
}
}
}
/**
* 文件类
*/
class FileSecurityComponent extends SecurityComponent{
public FileSecurityComponent(String componentName) {
super(componentName);
}
@Override
public void operation() {
System.out.println("打开文件["+this.componentName+"],展示文件----------");
}
}
/**
* 视频文件
*/
class VideoFileSecurityComponent extends FileSecurityComponent{
public VideoFileSecurityComponent(String componentName) {
super(componentName);
}
@Override
public void operation() {
System.out.println("Video文件使用Media Player打开文件["+this.componentName+"]------------------------");
}
}
/**
* 文本文件
*/
class TextFileSecurityComponent extends FileSecurityComponent{
public TextFileSecurityComponent(String componentName) {
super(componentName);
}
@Override
public void operation() {
System.out.println("Text文件使用记事本打开文件["+this.componentName+"]-------------------------------");
}
}
/**
* doc文件
*/
class DocFileSecurityComponent extends FileSecurityComponent{
public DocFileSecurityComponent(String componentName) {
super(componentName);
}
@Override
public void operation() {
System.out.println("doc文件使用Office工具打开文件["+this.componentName+"]-------------------------------");
}
}
安全组合类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JtkP9K0b-1682474816625)(设计模式学习20230406.assets/1682472182717.png)]
透明组合模式
/**
* 组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树状结构,并且能够像处理单个对象一样处理组合对象和单个对象。
*
* 在组合模式中,有两种基本类型的对象:叶子对象和组合对象。叶子对象是不能再被分解的基本单元,而组合对象由多个叶子对象或组合对象组成。这些对象组合形成了一个树形结构,根节点是一个组合对象,子节点可以是组合对象或叶子对象。
* 组合模式提供了一个一致的方式来处理树形结构中的所有对象。它通过统一处理叶子对象和组合对象来简化了客户端的代码,使得客户端可以像处理单个对象一样处理组合对象和叶子对象。同时,组合模式也保证了树形结构中的所有对象都可以被遍历到,无论是组合对象还是叶子对象。
* 组合模式通常使用递归的方式遍历树形结构,从而实现对所有对象的操作。在使用组合模式时,需要注意组合对象和叶子对象之间的区别,以及如何遍历整个树形结构。
*
* 是指将组合中的所有对象都视为具有相同的接口和属性,即叶子节点和容器节点都实现了相同的接口,使得客户端无需关心对象的具体类型,可以一致地对待叶子节点和容器节点。这种模式的好处是简化了客户端的代码,但是可能会带来安全性问题,因为客户端可以在不知情的情况下调用不适用于叶子节点的方法,导致程序出错。
*/
public class TransparentCompositePatternTest {
public static void main(String[] args) {
TransparentComponent transparentComponent = new FolderComponent("容器");
FolderComponent folderComponent1 = new FolderComponent("文件夹一");
FolderComponent folderComponent2 = new FolderComponent("文件夹二");
FolderComponent folderComponent3 = new FolderComponent("文件夹三");
FolderComponent folderComponent4 = new FolderComponent("文件夹四");
transparentComponent.addComponent(folderComponent4);
folderComponent4.addComponent(folderComponent1);
folderComponent4.addComponent(folderComponent2);
folderComponent4.addComponent(folderComponent3);
TransparentComponent folderComponent = new DocFileComponent("doc文件1");
TransparentComponent videoFileComponent = new VideoFileComponent("视频文件1");
TransparentComponent textFileComponent = new TextFileComponent("文本文件1");
folderComponent4.addComponent(textFileComponent);
folderComponent1.addComponent(folderComponent);
folderComponent1.addComponent(videoFileComponent);
folderComponent1.addComponent(textFileComponent);
folderComponent2.addComponent(videoFileComponent);
folderComponent3.addComponent(videoFileComponent);
transparentComponent.operation();
}
}
/**
* 场景举例:
* 现在存在需要设计对与文件夹和文件的打开方式
* 文件夹:通过点击打开,展示点击文件夹下所显示的所有文件以及文件夹
* 文件:针对与不同文件,需要使用不同的应用来打开
* txt文本:用记事本打开
* doc文件:用office打开
* video视频:使用media player打开
*/
abstract class TransparentComponent{
String componentName;
protected List<TransparentComponent> componentList;
public TransparentComponent(String componentName){
this.componentName=componentName;
this.componentList=new ArrayList<>();
}
public abstract void addComponent(TransparentComponent component);
public abstract void removeComponent(TransparentComponent component);
public abstract TransparentComponent getComponent(int index);
public abstract void operation();
}
/**
* 创建一个文件夹类
*/
class FolderComponent extends TransparentComponent{
public FolderComponent(String componentName) {
super(componentName);
}
@Override
public void addComponent(TransparentComponent component) {
this.componentList.add(component);
}
@Override
public void removeComponent(TransparentComponent component) {
this.componentList.remove(component);
}
@Override
public TransparentComponent getComponent(int index) {
return this.componentList.get(index);
}
@Override
public void operation() {
System.out.println("打开文件夹["+this.componentName+"]----------------------");
for (TransparentComponent transparentComponent : this.componentList) {
transparentComponent.operation();
}
}
}
/**
* 文件类
*/
class FileComponent extends TransparentComponent{
public FileComponent(String componentName) {
super(componentName);
}
@Override
public void addComponent(TransparentComponent component) {
System.out.println("文件不支持添加组件-----------------");
}
@Override
public void removeComponent(TransparentComponent component) {
System.out.println("文件不支持移除组件-----------------");
}
@Override
public TransparentComponent getComponent(int index) {
System.out.println("文件不支持获取组件-----------------");
return null;
}
@Override
public void operation() {
System.out.println("打开文件["+this.componentName+"],展示文件----------");
}
}
/**
* 视频文件
*/
class VideoFileComponent extends FileComponent{
public VideoFileComponent(String componentName) {
super(componentName);
}
@Override
public void operation() {
System.out.println("Video文件使用Media Player打开文件["+this.componentName+"]------------------------");
}
}
/**
* 文本文件
*/
class TextFileComponent extends FileComponent{
public TextFileComponent(String componentName) {
super(componentName);
}
@Override
public void operation() {
System.out.println("Text文件使用记事本打开文件["+this.componentName+"]-------------------------------");
}
}
/**
* doc文件
*/
class DocFileComponent extends FileComponent{
public DocFileComponent(String componentName) {
super(componentName);
}
@Override
public void operation() {
System.out.println("doc文件使用Office工具打开文件["+this.componentName+"]-------------------------------");
}
}
透明组合类图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZ99dDGT-1682474816626)(设计模式学习20230406.assets/1682472294936.png)]
装饰模式(Decorator Pattern)
动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
在装饰模式中,有一个抽象组件(Component)和若干个装饰器(Decorator),装饰器继承自抽象组件,实现与抽象组件相同的接口,并持有一个抽象组件的引用。这样就可以在运行时动态地给组件添加新的行为,而无需修改组件的源代码。
装饰模式分为以下两种模式:
- 透明装饰模式指的是,装饰者完全透明地包装了被装饰对象,对外表现为同一类型,即装饰者与被装饰者具有相同的接口。客户端无法感知被装饰者的存在,所有的操作都是通过装饰者完成的。透明装饰模式需要保证装饰者与被装饰者实现相同的接口,这样才能确保透明性,但也会导致装饰者和被装饰者的耦合度较高。
- 半透明装饰模式指的是,装饰者只包装了被装饰对象的一部分行为或职责,对外表现为部分相同的接口。客户端可以感知被装饰者的存在,也可以直接调用被装饰者的方法,同时也可以通过装饰者提供的额外接口来调用新增的行为或职责。半透明装饰模式降低了装饰者和被装饰者之间的耦合度,但也会使得客户端的代码更加复杂。
在装饰模式结构图中包含如下几个角色:
- Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
- ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
- Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
- ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
代码示例
/**
* 动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
* 在装饰模式中,有一个抽象组件(Component)和若干个装饰器(Decorator),
* 装饰器继承自抽象组件,
* 实现与抽象组件相同的接口,
* 并持有一个抽象组件的引用。
* 这样就可以在运行时动态地给组件添加新的行为,而无需修改组件的源代码
*
* 这样解决了类与类之间不能多继承,采用引用抽象组件(实例可以是具体的组件,也可以是装饰器装饰后的组件)来实现对原组件的扩展
*/
public class DecoratorPatternTest {
public static void main(String[] args) {
// 作为一杯咖啡,我们可以通过装饰器动态的添加其行为,比如给他增加加糖,绘制特殊图案
Component cafeComponent = new ConcreteComponent("咖啡");
TransparentDecorator sugarDecorator = new TransparentDecorator("加糖",cafeComponent) {
@Override
public void addBehaviour() {
System.out.println("对咖啡进行操作:" + this.operationName);
}
};
TransparentDecorator paintDecorator = new TransparentDecorator("绘制图案", sugarDecorator) {
@Override
public void addBehaviour() {
System.out.println("对咖啡进行操作:" + this.operationName);
}
};
paintDecorator.operation();
System.out.println("透明装饰模式---------------------------------------------------");
Component paintDecorator1 = new PaintDecorator(cafeComponent);
Component sugarDecorator1 = new SugarDecorator(paintDecorator1);
sugarDecorator1.operation();
System.out.println("半透明装饰模式-------------------------------------------------");
SemiTransparentSugarDecorator semiTransparentSugarDecorator = new SemiTransparentSugarDecorator(cafeComponent);
semiTransparentSugarDecorator.operation();
semiTransparentSugarDecorator.addBehaviour();
semiTransparentSugarDecorator.addOtherBehaviour();// 可以调用子类装饰器额外的方法,但需要明确子类,而不能用抽象类
}
}
abstract class Component{
public String componentName;
public Component(String componentName){
this.componentName=componentName;
}
public abstract void operation();
}
class ConcreteComponent extends Component{
public ConcreteComponent(String componentName) {
super(componentName);
}
@Override
public void operation() {
System.out.println("我是"+componentName);
}
}
abstract class TransparentDecorator extends Component{
protected Component component;
protected String operationName;
public TransparentDecorator(String operationName,Component component) {
super("装饰器");
this.operationName=operationName;
this.component= component;
}
@Override
public void operation() {
component.operation();
this.addBehaviour();
}
public abstract void addBehaviour();
}
class SugarDecorator extends TransparentDecorator{
public SugarDecorator(Component component) {
super("加糖", component);
}
@Override
public void addBehaviour() {
System.out.println("对"+this.component.componentName+"进行操作:"+this.operationName);
}
}
class PaintDecorator extends TransparentDecorator{
public PaintDecorator(Component component) {
super("绘制图案", component);
}
@Override
public void addBehaviour() {
System.out.println("对"+this.component.componentName+"进行操作:"+this.operationName);
}
}
abstract class SemiTransparentDecorator extends Component{
protected Component component;
protected String operationName;
public SemiTransparentDecorator(String operationName,Component component) {
super("装饰器");
this.operationName=operationName;
this.component= component;
}
@Override
public void operation() {
component.operation();
this.addBehaviour();
}
public abstract void addBehaviour();
}
class SemiTransparentSugarDecorator extends SemiTransparentDecorator{
public SemiTransparentSugarDecorator(Component component) {
super("加糖", component);
}
@Override
public void addBehaviour() {
System.out.println("对"+this.component.componentName+"进行操作:"+this.operationName);
}
public void addOtherBehaviour() {
System.out.println("对"+this.component.componentName+"进行操作:"+"其他操作行为");
}
}
外观模式(Facade Pattern)
是一种结构型设计模式,它提供了一个简单的接口,隐藏了系统中复杂的逻辑和接口,使得系统更加易于使用和理解。外观模式通常被用来封装一个复杂的子系统,为客户端提供一个简单的接口。客户端可以通过这个接口来访问子系统中的各个部分,而不必了解这些部分的具体实现。
外观模式通常包括一个外观类(Facade Class),这个类提供了一个简单的接口,封装了系统中的各个组件,同时提供了一些高级功能。客户端通过这个接口来使用系统中的各个组件,而不必了解这些组件的具体实现。
外观模式的优点在于:
- 简化了客户端的使用,降低了客户端的复杂度。
- 将系统的复杂性隐藏在外观类后面,提高了系统的安全性。
- 降低了客户端和系统之间的耦合度,增加了系统的灵活性和可维护性。
外观模式的缺点在于:
- 如果外观类的接口不够简单清晰,仍然可能导致客户端的复杂度增加。
- 外观模式可能会导致系统的性能降低,因为外观类需要处理客户端和系统之间的所有交互。
外观模式包含如下两个角色:
- Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。
- SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。
代码示例
/**
* 场景模拟:
* 正常人吃饭,需要自己学习菜谱,切菜,做饭,洗碗
* 而不同的人可能对于吃什么有不同的想法,每个人都需要去学习,自己花费许多时间去做饭
* 引入外观类,就好比饭店,我们只需要告诉饭店我们需要什么,饭店则会去帮我们做好
*
* 使用抽象外观类,可以将内部属性耦合性降低,可以通过扩充子类(不同的外观类)方式来适配不同的厨师,服务员,切菜师傅,以及做饭流程
* 外观类负责将其各个员工职责进行管理,而向外暴简单的接口,隐藏内部复杂的流程操作
*/
class HotelFacade{
private VegetableCutter vegetableCutter;
private Cook cook;
private Waiter waiter;
public HotelFacade(){
this.vegetableCutter = new VegetableCutter();
this.cook = new Cook();
this.waiter = new Waiter();
}
public void getSetMeal(String setMealName){
vegetableCutter.prepareIngredients();
cook.cook();
waiter.serving();
System.out.println("套餐:"+setMealName+"做好了");
}
}
class Visitor{
public String tellSetMealName(String setMealName){
return setMealName;
};
}
class Cook{
public void cook(){
System.out.println("厨师开始烹饪------------");
}
}
class VegetableCutter{
public void prepareIngredients(){
System.out.println("切菜师傅准备食材---------");
}
}
class Waiter{
public void serving(){
System.out.println("服务员上菜---------------");
}
}
abstract class AbstractHotelFacade{
public abstract void getSetMeal(String setMealName);
}
享元模式(Flyweight Pattern)
运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
享元模式分为以下两种模式
- 单纯享元模式(Flyweight Pattern)的核心思想是共享对象,通过共享减少对象的创建和消耗,从而提高系统的性能和效率。单纯享元模式中,共享的对象是不可变的,即共享对象的状态是只读的,不会被修改。因此,单纯享元模式适用于大量相似对象的场景,可以显著减少内存占用。
- 复合享元模式(Composite Flyweight Pattern)是在单纯享元模式的基础上进一步扩展的。复合享元模式中,共享对象不仅可以共享不变的状态,还可以共享可变的状态。复合享元模式将共享对象分为内部状态和外部状态两个部分,内部状态是不变的,可以共享;外部状态是可变的,不可以共享。通过这种方式,复合享元模式可以适用于更加复杂的场景,可以更加灵活地控制对象的状态。
定义:
- 享元模式又叫蝇量模式,通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免大量相似对象的开销,从而提高系统资源的利用率,即运用共享技术来有效地支持大量细粒度对象的复用。
享元模式的使用场景:
- 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源,因此,在需要多次重复使用享元对象时才值得使用享元模式。
- 享元模式常用于系统底层开发,解决系统的性能问题,典型应用场景便是池技术,如数据库连接池、字符串常量池、线程池、缓冲池等。
享元模式中的两种状态:
- 内部状态,不会随着环境的改变而改变的可共享部分,对对象的属性。
- 外部状态,随环境改变而改变的不可以共享的部分,享元模式的实现要领就是区分应用中的这两种状态,并将外部状态外部化,如对象的方法。
享元模式的成员角色及职责:
- 抽象享元角色(Flyweight):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。
- 具体享元角色(Concrete Flyweight) :它实现了抽象享元类,称为享元对象。在具体享元类中为内部状态提供了存储空间。通常可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。
- 非享元角色(Unsharable Flyweight) :并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类,当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
- 享元工厂角色(Flyweight Factory) :负责创建和管理享元角色,当客户对象请求一个享元对象时,享元工厂检查系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
理解内部状态和外部状态
内部状态(Intrinsic State):指那些可以被多个对象共享并在对象之间共用的状态信息,通常存储在享元对象内部。因为内部状态是可以共享的,所以它不会因为对象的数量而增加内存占用。
例如,如果我们要设计一个棋子游戏,其中有红色棋子和黑色棋子,那么棋子的形状、大小、颜色、以及移动方式等信息就是内部状态。因为这些信息对于所有的棋子都是相同的,所以我们可以将它们存储在享元对象内部。
外部状态(Extrinsic State):指那些因环境变化而不同的状态信息,这些信息不能被共享。外部状态是由客户端对象在使用享元对象时传入的,通常存储在客户端对象中。
继续以棋子游戏为例,假设我们在一个棋盘上使用棋子。那么每个棋子的位置信息就是外部状态,因为每个棋子的位置都是不同的,且会随着游戏进程而变化。这些位置信息会被客户端对象传递给享元对象,并且存储在客户端对象中。
因此,我们可以将棋子游戏中的内部状态和外部状态进行分离。将内部状态存储在享元对象内部,而将外部状态作为参数传递给享元对象。这样就可以减少对象的数量,提高系统的性能。
代码示例
/**
* 运用共享技术有效地支持大量细粒度对象的复用。
* 系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。
* 由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
*/
public class FlyweightTest {
public static void main(String[] args) throws CloneNotSupportedException {
Flyweight flyweight1 = FlyweightFactory.getFlyweight("白色棋子");
Flyweight flyweight2 = FlyweightFactory.getFlyweight("白色棋子");
System.out.println(flyweight1==flyweight2);
flyweight1.display();
flyweight1.setLocation(new Location(4,4));
flyweight1.display();
flyweight2.display();
flyweight2.setLocation(new Location(6,6));
flyweight2.display();
System.out.println(flyweight1.getChessInnerInfo()==flyweight2.getChessInnerInfo());
System.out.println(flyweight1.getLocation()==flyweight2.getLocation());
}
}
/**
* 享元工厂类,用于获取享元池(包含很多享元对象)
* 内部状态(Intrinsic State):指那些可以被多个对象共享并在对象之间共用的状态信息,通常存储在享元对象内部。因为内部状态是可以共享的,所以它不会因为对象的数量而增加内存占用。
* 例如,如果我们要设计一个棋子游戏,其中有红色棋子和黑色棋子,那么棋子的形状、大小、颜色、以及移动方式等信息就是内部状态。因为这些信息对于所有的棋子都是相同的,所以我们可以将它们存储在享元对象内部。
* 外部状态(Extrinsic State):指那些因环境变化而不同的状态信息,这些信息不能被共享。外部状态是由客户端对象在使用享元对象时传入的,通常存储在客户端对象中。
* 继续以棋子游戏为例,假设我们在一个棋盘上使用棋子。那么每个棋子的位置信息就是外部状态,因为每个棋子的位置都是不同的,且会随着游戏进程而变化。这些位置信息会被客户端对象传递给享元对象,并且存储在客户端对象中。
* 因此,我们可以将棋子游戏中的内部状态和外部状态进行分离。将内部状态存储在享元对象内部,而将外部状态作为参数传递给享元对象。这样就可以减少对象的数量,提高系统的性能。
*
* 如五子棋,分为白色、黑色
* 颜色,尺寸,材料为内部状态,位置为外部状态
* 我们只需要保证每个棋子的内部状态都指向相同的内部属性状态类,可以实现共用,减少内存开销,因为无论多少棋子,他们的内部属性都引用的享元池中对象。
*/
class FlyweightFactory{
private static Map<String,Flyweight> flyweights = new HashMap<>();
static {
flyweights.put("白色棋子",new ChessFlyweight(new WhiteConcreteChessInnerInfo()));
flyweights.put("黑色棋子",new ChessFlyweight(new BlackConcreteChessInnerInfo()));
}
// public static Map<String,Flyweight> getFlyweights(){
// return flyweights;
// }
public static Flyweight getFlyweight(String flyweightName) throws CloneNotSupportedException {
if (!flyweights.containsKey(flyweightName)) {
System.out.println("不存在对应[" + flyweightName + "]的享元对象!!!");
}
Flyweight flyweight = flyweights.get(flyweightName);
// flyweights.remove(flyweightName);
return (Flyweight)flyweight.clone();
}
public static Flyweight putFlyweight(String flyweightName,Flyweight flyweight){
if (!(flyweight instanceof ChessFlyweight)){
// System.out.println("该对象不是象棋享元模式,不能操作------");
throw new RuntimeException("该对象不是象棋享元模式,不能操作------");
}
ChessFlyweight chessFlyweight = (ChessFlyweight) flyweight;
if (chessFlyweight.getLocation() !=null){
throw new RuntimeException("该对象已被棋盘占用,不能放入棋盒中------");
}
flyweights.put(flyweightName,flyweight);
return flyweight;
}
}
abstract class Flyweight implements Cloneable {
protected ChessInnerInfo chessInnerInfo;
protected Location location;
public abstract Location getLocation();
public abstract ChessInnerInfo getChessInnerInfo();
public abstract void setLocation(Location location);
public abstract void display();
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class ChessFlyweight extends Flyweight{
public ChessFlyweight(ChessInnerInfo chessInnerInfo){
this.chessInnerInfo = chessInnerInfo;
}
public Location getLocation() {
return location;
}
public ChessInnerInfo getChessInnerInfo() {
return chessInnerInfo;
}
@Override
public void setLocation(Location location) {
this.location=location;
}
@Override
public void display() {
System.out.println("棋子的内部属性为:"+chessInnerInfo.toString()+" 棋子的外部属性为:"+(location==null?null:location.toString()));
}
}
class Location{
private int x;
private int y;
public Location(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "Location{" +
"x=" + x +
", y=" + y +
'}';
}
}
abstract class ChessInnerInfo{
protected String size;
protected String color;
protected String material;
@Override
public String toString() {
return "ChessInnerInfo{" +
"尺寸:'" + size + '\'' +
", 颜色:'" + color + '\'' +
", 材料:'" + material + '\'' +
'}';
}
}
class WhiteConcreteChessInnerInfo extends ChessInnerInfo{
public WhiteConcreteChessInnerInfo(){
this.size="small";
this.color="白色";
this.material="塑料";
};
}
class BlackConcreteChessInnerInfo extends ChessInnerInfo{
public BlackConcreteChessInnerInfo(){
this.size="small";
this.color="白色";
this.material="塑料";
};
}
代理模式Proxy Pattern
给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。
代理模式(Proxy Pattern)是一种结构型设计模式,其目的是通过代理对象控制对原始对象的访问。代理模式在访问对象时引入了一层间接层,这层间接层可以在访问对象前后执行一些额外的操作,如权限控制、缓存、日志记录等。
代理模式的核心是代理对象和原始对象,代理对象和原始对象都要实现同一个接口,这样代理对象就可以代理原始对象的所有行为。代理对象在执行原始对象的行为时,可以在行为前后执行一些额外的操作,例如记录日志、验证权限、缓存数据等。
代理模式有多种实现方式,其中最常见的是静态代理和动态代理:
- 静态代理:在编译时就已经确定代理对象和原始对象的关系,代理对象是通过手动编写代码实现的。静态代理的缺点是需要手动编写大量的代理类,不够灵活。
- 动态代理:在运行时动态地生成代理对象,代理对象不需要手动编写代码。动态代理的优点是可以在运行时动态地生成代理对象,更加灵活。
- 远程代理(Remote Proxy):远程代理是一种可以隐藏对象存在于不同地址空间的代理。远程代理可以在本地代理和远程对象之间进行通信,通过网络传输数据来实现代理对象和原始对象的交互。例如,当我们需要访问位于远程服务器上的对象时,就可以使用远程代理来进行访问。
- 虚拟代理(Virtual Proxy):虚拟代理是一种可以延迟对象的创建或加载的代理。虚拟代理可以在访问对象时,先创建一个占位符对象代替原始对象,等到需要使用原始对象时再进行创建或加载。例如,在网页中加载大量图片时,可以使用虚拟代理来实现图片的懒加载,避免页面加载过慢。
- 缓冲代理(Cache Proxy):缓冲代理是一种可以缓存对象的代理。缓冲代理可以在访问对象时,先查看缓存中是否已经存在该对象,如果存在则直接返回缓存中的对象,否则再创建一个新的对象。例如,在对数据库进行频繁查询时,可以使用缓冲代理来缓存查询结果,避免重复查询造成的性能问题。
代理模式包含如下三个角色:
- Subject(抽象主题角色):它声明了真实主题和代理主题的共同接口,这样一来在任何使用真实主题的地方都可以使用代理主题,客户端通常需要针对抽象主题角色进行编程。
- Proxy(代理主题角色):它包含了对真实主题的引用,从而可以在任何时候操作真实主题对象;在代理主题角色中提供一个与真实主题角色相同的接口,以便在任何时候都可以替代真实主题;代理主题角色还可以控制对真实主题的使用,负责在需要的时候创建和删除真实主题对象,并对真实主题对象的使用加以约束。通常,在代理主题角色中,客户端在调用所引用的真实主题操作之前或之后还需要执行其他操作,而不仅仅是单纯调用真实主题对象中的操作。
- RealSubject(真实主题角色):它定义了代理角色所代表的真实对象,在真实主题角色中实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的操作。
代码示例
/**
* 代理模式:其目的是通过代理对象控制对原始对象的访问。代理模式在访问对象时引入了一层间接层,这层间接层可以在访问对象前后执行一些额外的操作
*/
public class ProxyPatternTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("静态代理使用---------------------------------");
Person proxy = new Slave(new Master());
proxy.cooking();
System.out.println("动态代理使用---------------------------------");
Master master = new Master();
InvocationHandlerC invocationHandler = new InvocationHandlerC(master);
Person proxy1 = (Person)Proxy.newProxyInstance(ProxyPatternTest.class.getClassLoader(), Master.class.getInterfaces(), invocationHandler);
Person proxy2 = (Person)Proxy.newProxyInstance(ProxyPatternTest.class.getClassLoader(), Master.class.getInterfaces(), invocationHandler);
Person proxy3 = (Person)Proxy.newProxyInstance(ProxyPatternTest.class.getClassLoader(), Master.class.getInterfaces(), invocationHandler);
System.out.println(proxy1==proxy2);
System.out.println(proxy1==proxy3);
System.out.println(proxy1 instanceof Person);
System.out.println(proxy1 instanceof Proxy);
System.out.println(proxy1);
System.out.println(proxy2);
System.out.println(proxy3);
proxy1.cooking();
System.out.println(invocationHandler);
Thread.sleep(1000000);
}
}
class InvocationHandlerC implements InvocationHandler{
public Person person;
public InvocationHandlerC(Person person){
this.person=person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("买菜--------------");
Object invoke = method.invoke(person, args);
System.out.println("上菜---------------");
return invoke;
}
}
/**
* 场景举例:
* 我要吃饭,则我需要做饭,我可以请一个保姆来帮我做饭,保姆就相当于代理者,保姆把饭做好
*/
interface Person {
public void cooking();
}
class Master implements Person{
@Override
public void cooking() {
System.out.println("做饭.......");
}
}
/**
* 静态代理类
*/
class Slave implements Person{
private Person person;
public Slave(Person person){
this.person = person;
}
@Override
public void cooking() {
System.out.println("买菜--------------");
person.cooking();
System.out.println("上菜---------------");
}
}
// 动态代理生成代理类代码类如下:
/**
*
* package cn.study.zgm.gof23.designpattern.structpattern.proxypattern7;
*
* import java.lang.reflect.InvocationHandler;
* import java.lang.reflect.Method;
* import java.lang.reflect.Proxy;
* import java.lang.reflect.UndeclaredThrowableException;
*
* final class $Proxy0 extends Proxy implements Person {
* private static Method m1;
* private static Method m3;
* private static Method m2;
* private static Method m0;
*
* public $Proxy0(InvocationHandler var1) {
* super(var1);
* }
*
* static {
* try {
* m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
* m3 = Class.forName("cn.study.zgm.gof23.designpattern.structpattern.proxypattern7.Person").getMethod("cooking");
* m2 = Class.forName("java.lang.Object").getMethod("toString");
* m0 = Class.forName("java.lang.Object").getMethod("hashCode");
* } catch (NoSuchMethodException var2) {
* throw new NoSuchMethodError(var2.getMessage());
* } catch (ClassNotFoundException var3) {
* throw new NoClassDefFoundError(var3.getMessage());
* }
* }
*
* public final boolean equals(Object var1) {
* try {
* return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
* } catch (RuntimeException | Error var3) {
* throw var3;
* } catch (Throwable var4) {
* throw new UndeclaredThrowableException(var4);
* }
* }
*
* public final String toString() {
* try {
* return (String)super.h.invoke(this, m2, (Object[])null);
* } catch (RuntimeException | Error var2) {
* throw var2;
* } catch (Throwable var3) {
* throw new UndeclaredThrowableException(var3);
* }
* }
*
* public final int hashCode() {
* try {
* return (Integer)super.h.invoke(this, m0, (Object[])null);
* } catch (RuntimeException | Error var2) {
* throw var2;
* } catch (Throwable var3) {
* throw new UndeclaredThrowableException(var3);
* }
* }
*
* public final void cooking() {
* try {
* super.h.invoke(this, m3, (Object[])null);
* } catch (RuntimeException | Error var2) {
* throw var2;
* } catch (Throwable var3) {
* throw new UndeclaredThrowableException(var3);
* }
* }
* }
*/
可通过HSDB获取动态代理生成代理类
java -classpath "%JAVA_HOME%/lib/sa-jdi.jar" sun.jvm.hotspot.HSDB
职责链模式(Chain of Responsibility Pattern)
职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。
纯与不纯的职责链模式
职责链模式可分为纯的职责链模式和不纯的职责链模式两种:
纯的职责链模式
- 一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。而且在纯的职责链模式中,要求一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况。在前面的采购单审批实例中应用的是纯的职责链模式。
不纯的职责链模式
- 在一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。Java AWT 1.0中的事件处理模型应用的是不纯的职责链模式,其基本原理如下:由于窗口组件(如按钮、文本框等)一般都位于容器组件中,因此当事件发生在某一个组件上时,先通过组件对象的handleEvent()方法将事件传递给相应的事件处理方法,该事件处理方法将处理此事件,然后决定是否将该事件向上一级容器组件传播;上级容器组件在接到事件之后可以继续处理此事件并决定是否继续向上级容器组件传播,如此反复,直到事件到达顶层容器组件为止;如果一直传到最顶层容器仍没有处理方法,则该事件不予处理。每一级组件在接收到事件时,都可以处理此事件,而不论此事件是否在上一级已得到处理,还存在事件未被处理的情况。显然,这就是不纯的职责链模式,早期的Java AWT事件模型(JDK 1.0及更早)中的这种事件处理机制又叫事件浮升(Event Bubbling)机制。从Java.1.1以后,JDK使用观察者模式代替职责链模式来处理事件。目前,在JavaScript中仍然可以使用这种事件浮升机制来进行事件处理。
在职责链模式结构图中包含如下几个角色
- Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象(如结构图中的successor),作为其对下家的引用。通过该引用,处理者可以连成一条链。
- ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。
代码示例
/**
* 职责链模式
* 职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。
* 职责链模式分为存和不存的两种模式
* 纯的职责链模式、不纯的职责链模式
* 一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家
* 在一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收
*/
public class ChainOfResponsibilityPatternTest {
public static void main(String[] args) {
System.out.println("纯的职责链------------------------------------");
ScoreChain scoreHandleChain = ScoreChainManager.getScoreHandleChain();
ScoreLevelEnum scoreLevelEnum = scoreHandleChain.getScoreLevel(1000);
System.out.println("该成绩等级为:"+scoreLevelEnum.getLevel()+",等级判定规则为:"+scoreLevelEnum.getLevelRule());
System.out.println("不纯的职责链------------------------------------");
AskForLeaveChain chain = DefaultAskForLeaveChainManager.createChain();
chain.handle();
}
}
class DefaultAskForLeaveChainManager{
public static AskForLeaveChain createChain(){
AskForLeaveChain bossChain = new BossChain(null);
AskForLeaveChain divisionManagerChain = new DivisionManagerChain(bossChain);
AskForLeaveChain projectManagerChain = new ProjectManagerChain(divisionManagerChain);
return new HeadmanChain(projectManagerChain);
};
}
/**
* 纯的职责链模式,一个具体处理者对象只能在两个行为中选择一个
* 场景模拟:根据考试成绩判断属于优等生、差等生、中等生,返回不同的等级
*/
abstract class ScoreChain{
protected ScoreChain scoreChain;
public abstract ScoreLevelEnum getScoreLevel(int score);
}
class GoodScoreHandleChain extends ScoreChain{
public GoodScoreHandleChain(ScoreChain scoreChain){
this.scoreChain=scoreChain;
}
@Override
public ScoreLevelEnum getScoreLevel(int score) {
if (100>=score && score>=80){
return ScoreLevelEnum.GOOD;
}
return scoreChain==null?ScoreLevelEnum.NONE:scoreChain.getScoreLevel(score);
}
}
class NormalScoreHandleChain extends ScoreChain{
public NormalScoreHandleChain(ScoreChain scoreChain){
this.scoreChain=scoreChain;
}
@Override
public ScoreLevelEnum getScoreLevel(int score) {
if (80>=score && score>=60){
return ScoreLevelEnum.NORMAL;
}
return scoreChain==null?ScoreLevelEnum.NONE:scoreChain.getScoreLevel(score);
}
}
class BadScoreHandleChain extends ScoreChain{
public BadScoreHandleChain(ScoreChain scoreChain){
this.scoreChain=scoreChain;
}
@Override
public ScoreLevelEnum getScoreLevel(int score) {
if (60>=score && score>=0){
return ScoreLevelEnum.BAD;
}
return scoreChain==null?ScoreLevelEnum.NONE:scoreChain.getScoreLevel(score);
}
}
class ScoreChainManager{
public static ScoreChain getScoreHandleChain(){
BadScoreHandleChain badScoreHandleChain = new BadScoreHandleChain(null);
NormalScoreHandleChain normalScoreHandleChain = new NormalScoreHandleChain(badScoreHandleChain);
return new GoodScoreHandleChain(normalScoreHandleChain);
}
}
enum ScoreLevelEnum{
GOOD("优等生","大于等于80分小于等于100分"),
NORMAL("中等生","大于等于60分小于80分"),
BAD("差等生","大于等于0分小于60分"),
NONE("未匹配到","大于100分或者小于0分");
private String level;
private String levelRule;
ScoreLevelEnum(String level,String levelRule){
this.level=level;
this.levelRule=levelRule;
}
public String getLevel() {
return level;
}
public String getLevelRule() {
return levelRule;
}
}
/**
* 不纯的职责链模式:
* 场景模拟:员工需要走请假流程,
* 需要先等小组组长进行审批
* 审批后交由项目经理审批
* 审批后再交由部门经理审批
* 审批后最终交由老板审批
* 老板审批后通过
* 中间任一流程不通过,则需要被打回
*/
abstract class AskForLeaveChain{
protected AskForLeaveChain chain;
public AskForLeaveChain(AskForLeaveChain askForLeaveChain){
this.chain=askForLeaveChain;
}
public void handle(){
if (applyHandle()){
System.out.println(this+"流程通过");
supportHandle();
}else {
System.out.println(this+"处理不通过,流程结束");
}
};
public abstract Boolean applyHandle();
public void supportHandle(){
chain.handle();
};
// public void notSupportHandle(){
// chain.applyHandle();
// };
}
class HeadmanChain extends AskForLeaveChain{
public HeadmanChain(AskForLeaveChain askForLeaveChain){
super(askForLeaveChain);
}
@Override
public Boolean applyHandle() {
return true;
}
}
class ProjectManagerChain extends AskForLeaveChain{
public ProjectManagerChain(AskForLeaveChain askForLeaveChain){
super(askForLeaveChain);
}
@Override
public Boolean applyHandle() {
return true;
}
}
class DivisionManagerChain extends AskForLeaveChain{
public DivisionManagerChain(AskForLeaveChain askForLeaveChain){
super(askForLeaveChain);
}
@Override
public Boolean applyHandle() {
return false;
}
}
class BossChain extends AskForLeaveChain{
public BossChain(AskForLeaveChain askForLeaveChain){
super(askForLeaveChain);
}
@Override
public Boolean applyHandle() {
return true;
}
// boss执行完流程结束。
@Override
public void supportHandle(){
System.out.println("请假流程已走完,流程执行结束------------");
};
}
命令模式(Command Pattern)
将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
在命令模式结构图中包含如下几个角色:
● Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
● ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。
● Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
● Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理。
代码示例
/**
* 命令模式(Command Pattern)
* 将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
* 在命令模式结构图中包含如下几个角色:
* Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。
* ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。
* Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。
* Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理
*/
public class CommandPatternTest {
public static void main(String[] args) {
// 通过命令模式,我们可以灵活的组合接受者与命令之间的关系,通过不同的组合方式,来实现调用者和接受者之间的绑定
// 我们还可以使用工厂模式,来创建不同的开关
Invoker tvInvoker = ConcreteSwitchInvokerFactory.createTvInvoker();
Invoker microwaveOvenInvoker = ConcreteSwitchInvokerFactory.createMicrowaveOvenInvoker();
Invoker airConditioningInvoker = ConcreteSwitchInvokerFactory.createAirConditioningInvoker();
tvInvoker.invoke();
microwaveOvenInvoker.invoke();
airConditioningInvoker.invoke();
System.out.println("----CommandQueue命令---------------------------------------------");
CommandQueue commandQueue = new CommandQueue();
commandQueue.addCommand(new ConcreteCommand(new TVReceiver()));
commandQueue.addCommand(new ConcreteCommand(new MicrowaveOvenReceiver()));
commandQueue.addCommand(new ConcreteCommand(new AirConditioningReceiver()));
SwitchCommandQueueInvoker switchCommandQueueInvoker = new SwitchCommandQueueInvoker(commandQueue);
switchCommandQueueInvoker.call();
System.out.println("----CompositeCommand----------------------------------------------");
CompositeCommand tvCommand = new CompositeCommand();
CompositeCommand microwaveOvenCommand = new CompositeCommand();
tvCommand.add(new ConcreteCommand(new TVReceiver()));
microwaveOvenCommand.add(new ConcreteCommand(new MicrowaveOvenReceiver()));
CompositeCommand compositeCommand = new CompositeCommand();
compositeCommand.add(new ConcreteCommand(new AirConditioningReceiver()));
compositeCommand.add(tvCommand);
compositeCommand.add(microwaveOvenCommand);
SwitchInvoker switchInvoker = new SwitchInvoker(compositeCommand);
switchInvoker.invoke();
}
}
//abstract class SwitchInvokerFactory{
// public abstract Invoker createTvInvoker();
// public abstract Invoker createMicrowaveOvenInvoker();
// public abstract Invoker createAirConditioningInvoker();
//}
class ConcreteSwitchInvokerFactory{
public static Invoker createTvInvoker() {
// 开启电视
ConcreteCommand tvCommand = new ConcreteCommand(new TVReceiver());
return new SwitchInvoker(tvCommand);
}
public static Invoker createMicrowaveOvenInvoker() {
// 打开空调
ConcreteCommand microwaveOvenCommand = new ConcreteCommand(new MicrowaveOvenReceiver());
return new SwitchInvoker(microwaveOvenCommand);
}
public static Invoker createAirConditioningInvoker() {
// 打开微波炉
ConcreteCommand airConditioningCommand = new ConcreteCommand(new AirConditioningReceiver());
return new SwitchInvoker(airConditioningCommand);
}
}
/**
* 场景举例
* 一般在家中会存在很多开关,来控制不同的电器的开启/关闭
* 而开关和电器的关系在设计之前并不清楚,通过设计时开关和电器的电线连接来实现绑定,这个设计时可以灵活多变的,我们在设计程序时也应该遵守可以灵活变通,来实现开关与不同电器的关联
*/
abstract class Command{
public abstract void execute();
}
class CompositeCommand extends Command{
private List<Command> commandList;
public CompositeCommand(){
this.commandList= new ArrayList<>();
}
public void add(Command command){
commandList.add(command);
}
public void remove(Command command){
commandList.add(command);
}
public Command get(int i){
return commandList.get(i);
}
public void execute(){
for (Command command : commandList) {
command.execute();
}
};
}
abstract class Receiver{
public abstract void action();
}
abstract class Invoker{
public void invoke(){};
public void call(){};
}
class SwitchInvoker extends Invoker{
public Command command;
public SwitchInvoker(Command command){
this.command=command;
};
@Override
public void invoke() {
command.execute();
}
}
class SwitchCommandQueueInvoker extends Invoker{
public CommandQueue commandQueue;
public SwitchCommandQueueInvoker(CommandQueue commandQueue){
this.commandQueue=commandQueue;
};
@Override
public void call() {
commandQueue.call();
}
}
class SwitchCompositeCommandInvoker extends Invoker{
public Command command;
public SwitchCompositeCommandInvoker(Command command){
this.command=command;
};
@Override
public void invoke() {
command.execute();
}
}
class ConcreteCommand extends Command{
public Receiver receiver;
public ConcreteCommand(Receiver receiver){
this.receiver=receiver;
}
@Override
public void execute() {
receiver.action();
}
}
class TVReceiver extends Receiver{
@Override
public void action() {
this.turnOn();
}
public void turnOn(){
System.out.println("打开电视--------------------------");
}
public void turnOff(){
System.out.println("关闭电视--------------------------");
}
}
class AirConditioningReceiver extends Receiver{
@Override
public void action() {
this.turnOn();
}
public void turnOn(){
System.out.println("打开空调--------------------------");
}
public void turnOff(){
System.out.println("关闭空调--------------------------");
}
}
class MicrowaveOvenReceiver extends Receiver{
@Override
public void action() {
this.turnOn();
}
public void turnOn(){
System.out.println("打开微波炉--------------------------");
}
public void turnOff(){
System.out.println("关闭微波炉--------------------------");
}
}
//class State{
// private boolean turnOn;
// {
// turnOn = false;
// }
// public void setTurnOn(boolean turnOn){
// this.turnOn = turnOn;
// }
// public boolean getTurnOn(){
// return this.turnOn;
// }
//}
/*
* 实现命令队列,来对不同电器进行批量处理
*/
class CommandQueue{
public List<Command> commandList;
public CommandQueue(){
this.commandList= new ArrayList<>();
}
public void addCommand(Command command) {
commandList.add(command);
}
public void removeCommand(Command command) {
commandList.remove(command);
}
public void call(){
for (Command command : commandList) {
command.execute();
}
}
}
解释器模式(Interpreter Pattern)
定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的“语言”是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。
● AbstractExpression(抽象表达式):在抽象表达式中声明了抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共父类。
● TerminalExpression(终结符表达式):终结符表达式是抽象表达式的子类,它实现了与文法中的终结符相关联的解释操作,在句子中的每一个终结符都是该类的一个实例。通常在一个解释器模式中只有少数几个终结符表达式类,它们的实例可以通过非终结符表达式组成较为复杂的句子。
● NonterminalExpression(非终结符表达式):非终结符表达式也是抽象表达式的子类,它实现了文法中非终结符的解释操作,由于在非终结符表达式中可以包含终结符表达式,也可以继续包含非终结符表达式,因此其解释操作一般通过递归的方式来完成。
● Context(环境类):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。
代码示例
public class InterpreterPatternTest {
public static void main(String[] args) {
ExpressionInterpretUtils.interpret("down run 10 and left move 20 and up move 10 and left move 20 and up move 10");
ExpressionInterpretUtils.execute();
}
}
/**
* 场景举例:
* 通过代码实现对以下解析
* “down run 10 and left move 20”
* 控制程序向下 移动10 向左移动20
* 分别有direction(方向):down | up | left | right
* action(动作):run | move
* distance(距离):an integer
*/
abstract class AbstractInterpret{
public abstract String interpret();
}
// and 作为连接解释器,解释两个解释器关系
class AndInterpret extends AbstractInterpret{
private AbstractInterpret left;
private AbstractInterpret right;
public AndInterpret(AbstractInterpret left,AbstractInterpret right){
this.left = left;
this.right = right;
}
@Override
public String interpret() {
return left.interpret() + " 再 " + right.interpret();
}
}
class ExpressionInterpret extends AbstractInterpret{
private AbstractInterpret directionInterpret;
private AbstractInterpret actionInterpret;
private AbstractInterpret distanceInterpret;
public ExpressionInterpret(DirectionInterpret directionInterpret,ActionInterpret actionInterpret,DistanceInterpret distanceInterpret){
this.directionInterpret=directionInterpret;
this.actionInterpret=actionInterpret;
this.distanceInterpret=distanceInterpret;
}
@Override
public String interpret() {
return directionInterpret.interpret() + actionInterpret.interpret() + distanceInterpret.interpret();
}
}
class DirectionInterpret extends AbstractInterpret{
private String direction;
public DirectionInterpret(String direction){
this.direction=direction;
}
@Override
public String interpret() {
if ("up".equalsIgnoreCase(this.direction)){
return "向上";
}else if ("down".equalsIgnoreCase(this.direction)){
return "向下";
}else if ("left".equalsIgnoreCase(this.direction)){
return "向左";
}else if ("right".equalsIgnoreCase(this.direction)){
return "向右";
}else {
return "无效指令";
}
}
}
class ActionInterpret extends AbstractInterpret{
private String action;
public ActionInterpret(String action){
this.action=action;
}
@Override
public String interpret() {
if ("run".equalsIgnoreCase(this.action)){
return "快速移动";
}else if ("move".equalsIgnoreCase(this.action)){
return "移动";
}else {
return "无效指令";
}
}
}
class DistanceInterpret extends AbstractInterpret{
private String distance;
public DistanceInterpret(String distance){
this.distance=distance;
}
@Override
public String interpret() {
try{
Integer.parseInt(this.distance);
}catch (NumberFormatException e){
return "无效指令,距离必须为一个整数!";
}
return distance;
}
}
class ExpressionInterpretUtils{
private static AbstractInterpret abstractInterpret;
public static void interpret(String expression){
String[] commandList = expression.split("\\s+");
Stack stack = new Stack<>();
for (int i = 0; i < commandList.length; i++) {
// 第一个指令
if ("and".equalsIgnoreCase(commandList[i])){
AbstractInterpret pop = (AbstractInterpret)stack.pop();
//
++i;
String direction = commandList[i];
String action = commandList[++i];
String distance = commandList[++i];
DirectionInterpret directionInterpret = new DirectionInterpret(direction);
ActionInterpret actionInterpret = new ActionInterpret(action);
DistanceInterpret distanceInterpret = new DistanceInterpret(distance);
ExpressionInterpret expressionInterpret = new ExpressionInterpret(directionInterpret, actionInterpret, distanceInterpret);
AndInterpret andInterpret = new AndInterpret(pop,expressionInterpret);
stack.push(andInterpret);
}else{
String direction = commandList[i];
String action = commandList[++i];
String distance = commandList[++i];
DirectionInterpret directionInterpret = new DirectionInterpret(direction);
ActionInterpret actionInterpret = new ActionInterpret(action);
DistanceInterpret distanceInterpret = new DistanceInterpret(distance);
ExpressionInterpret expressionInterpret = new ExpressionInterpret(directionInterpret, actionInterpret, distanceInterpret);
stack.push(expressionInterpret);
}
}
ExpressionInterpretUtils.abstractInterpret = (AbstractInterpret)stack.pop();
}
public static void execute(){
System.out.println(abstractInterpret.interpret());
System.out.println("执行结束!");
}
}
迭代器模式(Iterator Pattern)
提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。
在迭代器模式结构图中包含如下几个角色:
● Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法,例如:用于获取第一个元素的first()方法,用于访问下一个元素的next()方法,用于判断是否还有下一个元素的hasNext()方法,用于获取当前元素的currentItem()方法等,在具体迭代器中将实现这些方法。
● ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对聚合对象的遍历,同时在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是一个表示位置的非负整数。
● Aggregate(抽象聚合类):它用于存储和管理元素对象,声明一个createIterator()方法用于创建一个迭代器对象,充当抽象迭代器工厂角色。
● ConcreteAggregate(具体聚合类):它实现了在抽象聚合类中声明的createIterator()方法,该方法返回一个与该具体聚合类对应的具体迭代器ConcreteIterator实例。
在迭代器模式中,提供了一个外部的迭代器来对聚合对象进行访问和遍历,迭代器定义了一个访问该聚合元素的接口,并且可以跟踪当前遍历的元素,了解哪些元素已经遍历过而哪些没有。迭代器的引入,将使得对一个复杂聚合对象的操作变得简单。
代码示例
/**
* 迭代器模式(Iterator Pattern)
* 提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。
*/
public class IteratorPatternTest {
public static void main(String[] args) {
AbstractObjectList objectList = new ObjectList();
objectList.add(1);
objectList.add(2);
objectList.add(3);
objectList.add(4);
objectList.add(5);
Iterator iterator = objectList.createIterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
if ((int)next%2==0){
iterator.remove();
// iterator.remove();
}
}
System.out.println("============================");
System.out.println(objectList.getObjects().toString());
}
}
/**
* ● Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法,例如:用于获取第一个元素的first()方法,用于访问下一个元素的next()方法,用于判断是否还有下一个元素的hasNext()方法,用于获取当前元素的currentItem()方法等,在具体迭代器中将实现这些方法。
* ● ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对聚合对象的遍历,同时在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是一个表示位置的非负整数。
* ● Aggregate(抽象聚合类):它用于存储和管理元素对象,声明一个createIterator()方法用于创建一个迭代器对象,充当抽象迭代器工厂角色。
* ● ConcreteAggregate(具体聚合类):它实现了在抽象聚合类中声明的createIterator()方法,该方法返回一个与该具体聚合类对应的具体迭代器ConcreteIterator实例。
*/
abstract class AbstractObjectList{
protected List<Object> objectList;
public AbstractObjectList(){
this.objectList=new ArrayList<>();
}
public abstract void add(Object o);
public abstract void remove(Object o);
public abstract Object get(int index);
public abstract List getObjects();
public abstract Iterator createIterator();
}
abstract class Iterator{
public abstract Boolean hasNext();
public abstract Object next();
public abstract Object getCurrent();
public abstract Object remove();
}
class ConcreteIterator extends Iterator{
private AbstractObjectList objectList;
private List list;
private int cursor1;
public ConcreteIterator(AbstractObjectList objectList){
this.objectList=objectList;
this.list=objectList.getObjects();
this.cursor1=0;
}
@Override
public Boolean hasNext() {
return cursor1<=list.size()-1;
}
@Override
public Object next() {
Object o = this.list.get(this.cursor1);
this.cursor1++;
return o;
}
@Override
public Object getCurrent() {
return this.list.get(this.cursor1);
}
@Override
public Object remove() {
this.cursor1--;
Object removeObject = this.list.remove(this.cursor1);
return removeObject;
}
}
class ObjectList extends AbstractObjectList {
@Override
public void add(Object o) {
objectList.add(o);
}
@Override
public void remove(Object o) {
objectList.remove(o);
}
@Override
public Object get(int index) {
return objectList.get(index);
}
@Override
public List getObjects() {
return this.objectList;
}
@Override
public Iterator createIterator() {
// return new ConcreteIterator(this);
return new ConcreteIterator1();
}
// 使用內部类实现迭代器,实现数据共享
/*
在迭代器模式结构图中,我们可以看到具体迭代器类和具体聚合类之间存在双重关系,其中一个关系为关联关系,在具体迭代器中需要维持一个对具体聚合对象的引用,该关联关系的目的是访问存储在聚合对象中的数据,以便迭代器能够对这些数据进行遍历操作。
除了使用关联关系外,为了能够让迭代器可以访问到聚合对象中的数据,我们还可以将迭代器类设计为聚合类的内部类,JDK中的迭代器类就是通过这种方法来实现的
*/
class ConcreteIterator1 extends Iterator{
private int cursor1;
private int lastRet;
public ConcreteIterator1(){
this.cursor1=0;
}
@Override
public Boolean hasNext() {
return cursor1<=objectList.size()-1;
}
@Override
public Object next() {
Object o = objectList.get(this.lastRet=this.cursor1);
this.cursor1++;
return o;
}
@Override
public Object getCurrent() {
return objectList.get(this.cursor1);
}
@Override
public Object remove() {
Object removeObject = objectList.remove(this.lastRet);
this.cursor1--;
this.lastRet=-1;
return removeObject;
}
}
}
中介者模式(Mediator Pattern)
用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
在中介者模式结构图中包含如下几个角色:
● Mediator(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。
● ConcreteMediator(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现协作行为,它维持了对各个同事对象的引用。
● Colleague(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。
● ConcreteColleague(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。
中介者模式的核心在于中介者类的引入,在中介者模式中,中介者类承担了两方面的职责:
(1) 中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,可通过中介者来实现间接调用。该中转作用属于中介者在结构上的支持。
(2) 协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致的和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。
代码示例
/**
* 用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
*/
public class MediatorPatternTest {
public static void main(String[] args) {
RentalMediator rentalMediator = new RentalMediator();
Colleague tenantColleague = new TenantColleague(rentalMediator);
Colleague homeownerColleague = new HomeownerColleague(rentalMediator);
rentalMediator.setTenantColleague(tenantColleague);
rentalMediator.setHomeownerColleague(homeownerColleague);
rentalMediator.mediatorBehavior();
}
}
/**
* 场景举例:
* 租房者、房产中介、房屋主人。
* 租房者 通过 房产中介进行找房子,房产中介带租房进行看房,房子满意,房产中介再通知房屋主人与租房者签订租房合同,到此,中介公司就完毕
*/
abstract class Mediator{
public abstract void mediatorBehavior();
}
abstract class Colleague{
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public void mediatorBehavior(){
mediator.mediatorBehavior();
};
public abstract void behavior();
}
class RentalMediator extends Mediator{
private Colleague tenantColleague;
private Colleague homeownerColleague;
public RentalMediator() {
}
public Colleague getTenantColleague() {
return tenantColleague;
}
public void setTenantColleague(Colleague tenantColleague) {
System.out.println("委托房屋给中介-----------------------------");
this.tenantColleague = tenantColleague;
}
public Colleague getHomeownerColleague() {
return homeownerColleague;
}
public void setHomeownerColleague(Colleague homeownerColleague) {
System.out.println("委托中介找房-----------------------------");
this.homeownerColleague = homeownerColleague;
}
//
@Override
public void mediatorBehavior() {
System.out.println("带租客看房-----------------------------------");
tenantColleague.behavior();
homeownerColleague.behavior();
}
}
class TenantColleague extends Colleague{
public TenantColleague(Mediator mediator) {
super(mediator);
}
@Override
public void behavior() {
System.out.println("租房者觉得房子还不错-----------------------");
}
}
class HomeownerColleague extends Colleague{
public HomeownerColleague(Mediator mediator) {
super(mediator);
}
@Override
public void behavior() {
System.out.println("房屋主人和租客签订合同----------------------");
}
}
备忘录模式(Memento Pattern)
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。
在备忘录模式结构图中包含如下几个角色:
● Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。
●Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同的编程语言中实现机制会有所不同。
●Caretaker(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无须知道对象的实现细节。
代码示例
/**
* 备忘录模式(Memento Pattern)
* 在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。
*/
public class MementoPatternTest {
public static void main(String[] args) {
ChessBaseInfo chessBaseInfo = new ChessBaseInfo("红色", "大");
Chess chess1 = new Chess(chessBaseInfo, "车", "1", new Location(1, 10));
Chess chess2 = new Chess(chessBaseInfo, "炮", "2", new Location(1, 1));
ChessOriginator chessOriginator = new ChessOriginator();
chessOriginator.add(chess1);
chessOriginator.add(chess2);
ChessCaretaker chessCaretaker = new ChessCaretaker();
chess1.display();
Memento memento = chessOriginator.create();
chess1.moveTo(new Location(1,8),memento);
chessCaretaker.saveMemento(memento);
chess1.display();
Memento memento1 = chessOriginator.create();
chess1.moveTo(new Location(3,2),memento1);
chessCaretaker.saveMemento(memento1);
chess2.display();
Memento memento2 = chessOriginator.create();
chess2.moveTo(new Location(2,2),memento2);
chessCaretaker.saveMemento(memento2);
chess2.display();
Memento memento3 = chessOriginator.create();
chess2.moveTo(new Location(3,3),memento3);
chessCaretaker.saveMemento(memento3);
System.out.println("悔棋--------------------------");
while (true){
Memento memento4 = chessCaretaker.getMemento();
if (memento4 != null){
chessOriginator.undo(memento4);
}else{
break;
}
}
}
}
/**
* 在备忘录模式结构图中包含如下几个角色:
* ● Originator(原发器):它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。
* ● Memento(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同的编程语言中实现机制会有所不同。
* ● Caretaker(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无须知道对象的实现细节。
* 场景举例:
* 中国象棋中需要增加悔棋操作,通过备忘录进行存储棋子的状态(可以实现多次撤销)
*/
abstract class Originator{
public abstract Memento create();
public abstract Chess get(String id);
public abstract void add(Chess chess);
public abstract void undo(Memento memento);
}
class ChessOriginator extends Originator{
private Map<String,Chess> chessMap = new HashMap<>();
@Override
public Memento create() {
return new ChessMemento();
}
@Override
public Chess get(String id) {
return chessMap.get(id);
}
@Override
public void add(Chess chess) {
chessMap.put(chess.getId(),chess);
}
@Override
public void undo(Memento memento) {
ChessMemento chessMemento = (ChessMemento) memento;
Chess chess = chessMap.get(chessMemento.getId());
// chess.display();
chess.moveTo(chessMemento.getOldLocation(),null);
chess.display();
}
}
abstract class Memento{
public abstract void save(Location oldLocation,Location newLocation,String chessId);
}
abstract class Caretaker{
public abstract void saveMemento(Memento memento);
public abstract Memento getMemento();
}
class ChessCaretaker extends Caretaker{
private Stack<Memento> stackMemento = new Stack();
@Override
public void saveMemento(Memento memento) {
stackMemento.push(memento);
}
@Override
public Memento getMemento() {
return stackMemento.empty()?null:stackMemento.pop();
// return stackMemento.pop();
}
}
class ChessMemento extends Memento{
private String id;
private Location oldLocation;
private Location newLocation;
@Override
public void save(Location oldLocation,Location newLocation,String chessId) {
this.oldLocation=oldLocation;
this.newLocation=newLocation;
this.id=chessId;
}
public String getId() {
return id;
}
public Location getOldLocation() {
return oldLocation;
}
public Location getNewLocation() {
return newLocation;
}
}
class ChessBaseInfo{
private String color;
private String size;
public ChessBaseInfo(String color, String size) {
this.color = color;
this.size = size;
}
@Override
public String toString() {
return "ChessBaseInfo{" +
"颜色='" + color + '\'' +
", 尺寸='" + size + '\'' +
'}';
}
}
class Location{
private int x;
private int y;
public Location(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "Location{" +
"x=" + x +
", y=" + y +
'}';
}
}
class Chess{
private ChessBaseInfo chessBaseInfo;
private String name;
private String id;
private Location location;
public String getId() {
return id;
}
public Chess(ChessBaseInfo chessBaseInfo, String name, String id, Location location) {
this.chessBaseInfo = chessBaseInfo;
this.name = name;
this.id = id;
this.location = location;
}
public void moveTo(Location location,Memento memento){
if (memento!=null){
Location oldLocation = this.location;
Location newLocation = location;
memento.save(oldLocation,newLocation,id);
}
this.location=location;
}
public void display(){
System.out.println("该象棋为:【"+name+"】"+",id="+id+",基本信息:"+chessBaseInfo.toString()+",位置信息:"+location.toString());
}
}
观察者模式(Observer Pattern)
定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
在观察者模式结构图中包含如下几个角色:
● Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。
● ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。
● Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。
● ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。
代码示例
/**
* 观察者模式(Observer Pattern)
* 定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
*/
public class ObserverPatternTest {
public static void main(String[] args) {
Subject subject = new ConcreteSubject("公众号");
subject.add(new ConcreteObserver("订阅者一"));
subject.add(new ConcreteObserver("订阅者二"));
subject.add(new ConcreteObserver("订阅者三"));
// subject.sendMsg("数据");
ConcreteProducer producer = new ConcreteProducer(subject, "生产者");
producer.sendMsg("哈哈,我是生产者,第一次建立连接,打声招呼");
}
}
/**
* 模拟观察者 和被观察者之间关系
* 同时可以通过设计生产者Producer将观察者当作消费者Consumer来使用
*/
interface Subject{
void notifyObservers();
void add(Observer observer);
void remove(Observer observer);
void sendMsg(Object msg);
String getSubjectName();
}
class ConcreteSubject implements Subject{
private String name;
private Object msg;
private List<Observer> observerList;
public ConcreteSubject(String name){
this.name=name;
observerList=new ArrayList<>();
};
@Override
public void notifyObservers() {
for (Observer observer : observerList) {
observer.update(this,msg);
}
}
@Override
public void add(Observer observer) {
observerList.add(observer);
}
@Override
public void remove(Observer observer) {
observerList.remove(observer);
}
@Override
public void sendMsg(Object msg) {
this.msg=msg;
notifyObservers();
this.msg = null;
}
@Override
public String getSubjectName() {
return this.name;
}
}
interface Observer{
public void update(Subject subject,Object arg);
}
class ConcreteObserver implements Observer{
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(Subject subject,Object arg) {
String msg = (String) arg;
// System.out.println("感知到了事件变化--------------");
System.out.println("观察者【"+name+"】,收到订阅者:【"+subject.getSubjectName()+"】发送的消息:"+msg);
}
}
interface Producer{
void sendMsg(Object args);
}
class ConcreteProducer implements Producer{
private Subject subject;
public ConcreteProducer(Subject subject,String name) {
this.subject = subject;
}
@Override
public void sendMsg(Object args) {
subject.sendMsg(args);
}
}
状态模式(State Pattern)
允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。
在状态模式结构图中包含如下几个角色:
● Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
● State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
● ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
在状态模式的使用过程中,一个对象的状态之间还可以进行相互转换,通常有两种实现状态转换的方式:
(1) 统一由环境类来负责状态之间的转换,此时,环境类还充当了状态管理器(State Manager)角色,在环境类的业务方法中通过对某些属性值的判断实现状态转换,还可以提供一个专门的方法用于实现属性判断和状态转换,如下代码片段所示:
public void changeState() {
//判断属性值,根据属性值进行状态转换
if (value == 0) {
this.setState(new ConcreteStateA());
}
else if (value == 1) {
this.setState(new ConcreteStateB());
}
......
}
(2) 由具体状态类来负责状态之间的转换,可以在具体状态类的业务方法中判断环境类的某些属性值再根据情况为环境类设置新的状态对象,实现状态转换,同样,也可以提供一个专门的方法来负责属性值的判断和状态转换。此时,状态类与环境类之间就将存在依赖或关联关系,因为状态类需要访问环境类中的属性值,如下代码片段所示:
public void changeState(Context ctx) {
//根据环境对象中的属性值进行状态转换
if (ctx.getValue() == 1) {
ctx.setState(new ConcreteStateB());
}
else if (ctx.getValue() == 2) {
ctx.setState(new ConcreteStateC());
}
......
}
代码示例
/**
* 状态模式(State Pattern)
* 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式
*/
public class StatePatternTest {
public static void main(String[] args) {
Switch aSwitch = new Switch();
aSwitch.getState().display();
aSwitch.change();
aSwitch.getState().display();
aSwitch.change();
aSwitch.getState().display();
aSwitch.change();
aSwitch.getState().display();
aSwitch.change();
aSwitch.getState().display();
aSwitch.change();
aSwitch.getState().display();
}
}
/**
* 在状态模式结构图中包含如下几个角色:
* ● Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
* ● State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为,在抽象状态类中声明了各种不同状态对应的方法,而在其子类中实现类这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。
* ● ConcreteState(具体状态类):它是抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
*/
/**
* 场景举例:
* 模拟开关:一般开关存在两种状态,打开/关闭 两种状态
* 针对于按钮存在有两种促发方式(比如:开启按钮向右旋转,关闭向左旋转,此时按钮状态就需要进行判断触发)
* 已经处于开启状态的就不允许继续开启(向右旋转) turn on
* 已经处于关闭状态的就不允许继续关闭(向左旋转) turn off
* change:用于状态切换
* 在状态模式的使用过程中,一个对象的状态之间还可以进行相互转换,通常有两种实现状态转换的方式:
* (1) 统一由环境类来负责状态之间的转换(就在环境类中用if判断属于哪个状态,再执行对应状态的方法)
* (2) 由具体状态类来负责状态之间的转换(下列代码使用状态类来区分)
*/
class Switch{
private SwitchState state = new SwitchOffState();
public static SwitchState switchOffState = new SwitchOffState();
public static SwitchState switchOnState = new SwitchOnState();
public void setState(SwitchState state) {
this.state = state;
}
public SwitchState getState() {
return this.state;
}
//打开开关
public void on() {
state.turnOn(this);
}
//关闭开关
public void off() {
state.turnOff(this);
}
public void change(){
state.change(this);
}
}
interface SwitchState{
public void display();
public void turnOn(Switch s);
public void turnOff(Switch s);
public void change(Switch s);
public SwitchStateEnum getStateEnum();
}
class SwitchOnState implements SwitchState{
private SwitchStateEnum ON_STATE = SwitchStateEnum.ON_STATE;
public SwitchStateEnum getStateEnum() {
return ON_STATE;
}
@Override
public void display() {
System.out.println("当前开关状态为:"+ON_STATE.getStatus());
}
@Override
public void turnOn(Switch s) {
System.out.println("打开失败!开关已处于打开状态--------");
}
@Override
public void turnOff(Switch s) {
System.out.println("关闭开关!---------------------------");
s.setState(Switch.switchOffState);
}
@Override
public void change(Switch s) {
System.out.println("关闭开关!---------------------------");
s.setState(Switch.switchOffState);
}
}
class SwitchOffState implements SwitchState{
private SwitchStateEnum OFF_STATE = SwitchStateEnum.OFF_STATE;
public SwitchStateEnum getStateEnum() {
return OFF_STATE;
}
@Override
public void display() {
System.out.println("当前开关状态为:"+OFF_STATE.getStatus());
}
@Override
public void turnOn(Switch s) {
System.out.println("打开开关!---------------------------");
s.setState(Switch.switchOnState);
}
@Override
public void turnOff(Switch s) {
System.out.println("关闭失败!当前开关已处于关闭状态!");
}
@Override
public void change(Switch s) {
System.out.println("打开开关!---------------------------");
s.setState(Switch.switchOnState);
}
}
enum SwitchStateEnum{
ON_STATE("on"),OFF_STATE("off");
private String status;
SwitchStateEnum(String status){
this.status=status;
}
public String getStatus() {
return status;
}
}
策略模式(Strategy Pattern)
定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。
在策略模式结构图中包含如下几个角色:
● Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
● Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
● ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。
代码示例
/**
策略模式(Strategy Pattern)
定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。
* 在策略模式结构图中包含如下几个角色:
* ● Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
* ● Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
* ● ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。
*/
public class StrategyPatternTest {
public static void main(String[] args) {
Context context = new Context(new AirConcreteStrategy());
context.goToTheSestination();
}
}
class Context{
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void goToTheSestination(){
strategy.travelStrategy();
}
}
/**
* 场景举例:
* 出行旅游:可以选择坐客车、坐火车、坐汽车多种方案
* 游客自身根据自己的预算,进行选择
*/
interface Strategy{
void travelStrategy();
}
class AirConcreteStrategy implements Strategy{
@Override
public void travelStrategy() {
System.out.println("飞机起飞了,即将到达目的地---------------");
}
}
class TrainConcreteStrategy implements Strategy{
@Override
public void travelStrategy() {
System.out.println("火车出发了,即将到达目的地---------------");
}
}
class AutomobileConcreteStrategy implements Strategy{
@Override
public void travelStrategy() {
System.out.println("汽车开动了,即将到达目的地---------------");
}
}
模板方法模式(Template Method Pattern)
定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式包含如下两个角色:
- AbstractClass(抽象类):在抽象类中定义了一系列基本操作(PrimitiveOperations),这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
- ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。
在实现模板方法模式时,开发抽象类的软件设计师和开发具体子类的软件设计师之间可以进行协作。一个设计师负责给出一个算法的轮廓和框架,另一些设计师则负责给出这个算法的各个逻辑步骤。实现这些具体逻辑步骤的方法即为基本方法,而将这些基本方法汇总起来的方法即为模板方法,模板方法模式的名字也因此而来。
下面将详细介绍模板方法和基本方法:
- 模板方法一个模板方法是定义在抽象类中的、把基本操作方法组合在一起形成一个总算法或一个总行为的方法。这个模板方法定义在抽象类中,并由子类不加以修改地完全继承下来。模板方法是一个具体方法,它给出了一个顶层逻辑框架,而逻辑的组成步骤在抽象类中可以是具体方法,也可以是抽象方法。由于模板方法是具体方法,因此模板方法模式中的抽象层只能是抽象类,而不是接口。
- 基本方法是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:抽象方法(Abstract Method)、具体方法(Concrete Method)和钩子方法(Hook Method)。
- 抽象方法:一个抽象方法由抽象类声明、由其具体子类实现。在C#语言里一个抽象方法以abstract关键字标识。
- 具体方法:一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
- 钩子方法:一个钩子方法由一个抽象类或具体类声明并实现,而其子类可能会加以扩展。通常在父类中给出的实现是一个空实现(可使用virtual关键字将其定义为虚函数),并以该空实现作为方法的默认实现,当然钩子方法也可以提供一个非空的默认实现。
代码示例
/**
* 模板方法模式(Template Method Pattern)
* 定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
*/
public class TemplateMethodPatternTest {
public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClass();
abstractClass.templateMethod();
AbstractClass1 abstractClass1 = new ConcreteClass1();
abstractClass1.templateMethod();
System.out.println("//");
ConcreteClass2 concreteClass2 = new ConcreteClass2(new ConcreteStrategy());
concreteClass2.templateMethod();
}
}
/**
* - AbstractClass(抽象类):在抽象类中定义了一系列基本操作(PrimitiveOperations),这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
* - ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。
*/
// 定义模板类
abstract class AbstractClass{
// 抽象方法:子类必须进行实现属于自身的执行流程
abstract void method1();
// 提供默认实现
public void method2(){
System.out.println("我是父类method2()方法-------------------------------");
};
// 提供空实现,子类可以根据情况自行进行扩展
void method3(){}
// 编写模板方法执行流程,使得子类可以扩充其他方法来实现不同的执行流程方式
// 提供统一的执行流程
public void templateMethod(){
method1();
method2();
method3();
};
}
class ConcreteClass extends AbstractClass{
@Override
void method1() {
System.out.println("我是子类method1()方法------------------------------");
}
}
abstract class AbstractClass1{
// 抽象方法:子类必须进行实现属于自身的执行流程
abstract void method1();
// 提供默认实现
public boolean method2(){
return true;
};
// 提供空实现,子类可以根据情况自行进行扩展
void method3(){}
// 编写模板方法执行流程,使得子类可以扩充其他方法来实现不同的执行流程方式
// 提供统一的执行流程
public void templateMethod(){
method1();
if (method2()){
method3();
}else {
System.out.println("method2()不满足,不能执行-----------------");
}
};
}
class ConcreteClass1 extends AbstractClass1{
@Override
public void method1() {
System.out.println("我是子类method1()方法------------------------------");
}
@Override
public boolean method2() {
return false;
}
@Override
public void method3() {
System.out.println("我是子类method3()方法,我执行了------------------------------");
}
}
//引入第三方类:模板方法中指定方法执行流程
class ConcreteClass2{
Strategy strategy;
public ConcreteClass2(Strategy strategy) {
this.strategy = strategy;
}
// 定义模板方法 结合策略模式来完成
void templateMethod(){
if (strategy.supportMethod()){
strategy.executeMethod();
}
}
}
interface Strategy{
boolean supportMethod();
void executeMethod();
}
class ConcreteStrategy implements Strategy {
@Override
public boolean supportMethod() {
return true;
}
@Override
public void executeMethod() {
System.out.println("方法执行了-----------------------");
}
}
访问者模式(Visitor Pattern)
提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
在访问者模式结构图中包含如下几个角色:
●Vistor(抽象访问者):抽象访问者为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道需要访问的具体元素的类型,具体访问者需要实现这些操作方法,定义对这些元素的访问操作。
●ConcreteVisitor(具体访问者):具体访问者实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素。
●Element(抽象元素):抽象元素一般是抽象类或者接口,它定义一个accept()方法,该方法通常以一个抽象访问者作为参数。【稍后将介绍为什么要这样设计。】
●ConcreteElement(具体元素):具体元素实现了accept()方法,在accept()方法中调用访问者的访问方法以便完成对一个元素的操作。
● ObjectStructure(对象结构):对象结构是一个元素的集合,它用于存放元素对象,并且提供了遍历其内部元素的方法。它可以结合组合模式来实现,也可以是一个简单的集合对象,如一个List对象或一个Set对象。
代码示例
/**
访问者模式(Visitor Pattern)
提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式
针对于不同的对象,同个访问者可以采取不同的处理方式,不需要通过去通过 显示判断对象类型进行相应的处理
*/
public class VisitorPatternTest {
public static void main(String[] args) {
NumberManager numberManager = new NumberManager();
numberManager.add(new TwoNumber(2));
numberManager.add(new TwoNumber(4));
numberManager.add(new TwoNumber(6));
numberManager.add(new OneNumber(1));
numberManager.add(new OneNumber(3));
numberManager.add(new OneNumber(5));
System.out.println("访问者1----------------------------------");
numberManager.accept(new VisitorOne());
System.out.println("访问者2----------------------------------");
numberManager.accept(new VisitorTwo());
}
}
interface Visitor{
public void visit(TwoNumber number);
public void visit(OneNumber number);
}
/**
* 对偶数*2
* 奇数*3
*/
class VisitorOne implements Visitor{
@Override
public void visit(TwoNumber number) {
System.out.println("我是偶数数:"+number.getNumber()+" 进行操作*2 |"+number.getNumber()*2);
}
@Override
public void visit(OneNumber number) {
System.out.println("我是奇数:"+number.getNumber()+" 进行操作*3 |"+number.getNumber()*3);
}
}
class VisitorTwo implements Visitor{
@Override
public void visit(TwoNumber number) {
System.out.println("我是偶数数:"+number.getNumber()+" 进行操作*5 |"+number.getNumber()*5);
}
@Override
public void visit(OneNumber number) {
System.out.println("我是奇数:"+number.getNumber()+" 进行操作*6 |"+number.getNumber()*6);
}
}
/**
*
*/
abstract class Number{
private int number;
public Number(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
abstract void accept(Visitor visitor);
}
class TwoNumber extends Number{
public TwoNumber(int number) {
super(number);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class OneNumber extends Number{
public OneNumber(int number) {
super(number);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class NumberManager{
private List<Number> numberList = null;
public NumberManager() {
this.numberList = new ArrayList<>();
}
public void accept(Visitor visitor){
for (Number number : numberList) {
number.accept(visitor);
}
}
public void add(Number number){
this.numberList.add(number);
};
}
代理模式和外观模式区别
- 代理模式是通过一个代理类来控制对另一个对象的访问,代理类与被代理类实现相同的接口,可以在方法调用前后加入自己的逻辑。代理模式的主要作用是控制对象的访问,可以实现对象的延迟加载、缓存、安全控制等。代理模式的经典例子是虚拟代理,它将实际的对象加载到内存中的时间延迟到真正需要使用时才进行。
- 外观模式是为了简化客户端与复杂子系统之间的交互,它提供一个高层次的接口来隐藏子系统的复杂性。外观模式的主要作用是简化接口,提供一个更加易用的接口。外观模式的经典例子是操作系统的图形用户界面(GUI),它提供了一个简单的接口来与底层的操作系统进行交互。
状态模式和策略模式的区别
- 状态模式用于管理对象在不同状态下的行为。它将对象的状态和行为分离开来,使得对象在不同状态下可以表现出不同的行为。状态模式的重点在于状态之间的转换,即在某个状态下调用某个方法会导致状态的改变,从而改变对象的行为。
- 策略模式则是用于管理对象的多种行为算法。它将行为算法封装成单独的策略类,然后在运行时根据具体情况选择使用哪个策略类。策略模式的重点在于算法的选择,即在运行时根据不同的情况选择不同的算法,以达到最优的效果。