JAVA 23种设计模式示例

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

一.单例模式

二.工厂方法模式

三.抽象工厂模式

四.建造者模式

五.原型模式

六.享元模式

七.门面模式

八.适配器模式

九.装饰者模式

十.策略模式

十一.模板方法模式

十二.观察者模式

十三.责任链模式

十四.代理模式

十五.桥接模式

十六.组合模式

十七.命令模式

十八.状态模式

十九.中介者模式

二十.迭代器模式

二十一.访问者模式

二十二.备忘录模式

二十三.解释器模式


一.单例模式

某个类只能生成一个实例该类提供了一个全局访问点供外部获取该实例。

1.懒汉模式延时加载只有在真正使用到的时候才进行实例化。

public class LazySingleton {
	
	private volatile static LazySingleton instance = null;
	
	private LazySingleton() {
		
	}
	
	public static LazySingleton getInstance() {
		if(null == instance) {
			synchronized (LazySingleton.class) {
				if(null == instance) {
					instance = new LazySingleton();
				}
			}
		}
		return instance;
	}
	
}

(1线程安全问题

(2double check加锁优化

(3编译器(JITCPU对满足as-if-series的指令会进行指令重排会导致获取到未初始化的实例所以需要加上volatile关键字进行修饰防止指令重排(创建一个对象需要经过开辟空间、赋默认值、初始化的过程。

2.饿汉模式

只有在真正主动使用对应的类时才会触发初始化例如(当前类时启动类即main函数所在类直接进行new操作访问静态属性、访问静态方法用反射访问类等;类加载的初始化阶段就完成了实例的初始化本质上就是借助于jvm类加载机制保证实例的唯一性(初始化过程只会执行一次及线程安全(JVM以同步的形式来完成类加载的整个过程。

类加载过程

(1加载二进制数据到内存中生成对应的class数据结构

(2连接a.验证b.准备(给类的静态成员变量赋默认值c.解析

(2初始化给类的静态变量赋初值

public class HungrySingleton {

	public static String name = "qingyun";
	private static HungrySingleton instance = new HungrySingleton();

	
	private HungrySingleton() {
		
	}
	
	public static HungrySingleton getInstance() {
		return instance;
	}
	
}

使用静态内部类实现饿汉模式

public class InnerClassSingleton {
	
	public static String name= "qingyun";
	
	private InnerClassSingleton() {
		
	}
	
	private static class SingletonHolder{
		private static InnerClassSingleton instance = new InnerClassSingleton();
	}
	
	public static InnerClassSingleton getInstance() {
		return SingletonHolder.instance;
	}
	
}

当访问静态name属性时不会加载instance的初始化只有真正使用到对应的类时才会初始化例如调用InnerClassSingleton.getInstance()。

要想反编译查看类加载的过程可以通过idea的Terminal查看进入class所在的目录执行javap命令

3.使用序列化、反序列化的方式创建单例需要保证类的唯一性。

(1把类序列化

类需要实现Serializable接口并且需要设置serialVersionUID 的值使用jdk自带的ObjectOutputStream把类序列化到磁盘上。

public class LazySingletonMain {

    public static void main(String[] args) {
        try {
            //获取实体
            LazySingleton instance = LazySingleton.getInstance();
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("name"));
            oos.writeObject(instance);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class LazySingleton implements Serializable {
    private static final long serialVersionUID = 1L;

    private volatile static LazySingleton instance = null;

    private LazySingleton() {

    }

    public static LazySingleton getInstance() {
        if(null == instance) {
            synchronized (LazySingleton.class) {
                if(null == instance) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

执行完后会生产序列化的文件

 (2把类反序列化保证是单例的

使用jdk自带的ObjectInputStream把序列化的类反序列化这样使用序列化的方式进行单例创建才能保证唯一性。

public class LazySingletonMain {

    public static void main(String[] args) {
        try {
            LazySingleton instance = LazySingleton.getInstance();
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("name"));
            //反序列化实体
            LazySingleton lazySingleton = (LazySingleton)ois.readObject();
            System.out.println(lazySingleton == instance);  //输出true
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class LazySingleton implements Serializable {
    //需要制定版本才能在序列化和反序列化中匹配为同一个实体
    private static final long serialVersionUID = 1L;

    private volatile static LazySingleton instance = null;

    private LazySingleton() {

    }

    public static LazySingleton getInstance() {
        if(null == instance) {
            synchronized (LazySingleton.class) {
                if(null == instance) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }

    //反序列化的时候生成实体时执行此处代码
    private Object readResolve() throws ObjectStreamException {
        return getInstance();
    }
}

二.工厂方法模式

Factory Method 定义一个用于创建对象的接口让子类决定实例化哪一个类。工厂方法模式使得一个类的实例化延时到子类。

应用场景

1.当你不知道该使用对象的确切类型的时候;

2.当你希望为库或框架提供扩展其它内部组件的方法时。

主要优点

1.将具体产品和创建者解耦;

2.符合单一职责原则;

3.符合开闭原则。

public class FactoryMethod {

    public static void main(String[] args) {
        //创建子类使用继承的父类来接收
        //Application application = new CreateProductA();
        Application application = new CreateProductB();
        //使用接口类来接收创建出来类体现了多态
        Product productObject = application.getProduct();
        //创建的是哪个类调用到的就是哪个类的方法实现
        productObject.method();
    }
}

//定义一个接口类
interface Product{
    public void method();
}

//类实现了接口必须实现接口中的方法
class ProductA implements Product{
    @Override
    public void method() {
        System.out.println("ProductA method");
    }
}


class ProductB implements Product{
    @Override
    public void method() {
        System.out.println("ProductB method");
    }
}

//抽象类里面不一定要有抽象方法;有抽象方法类必须要是抽象类
abstract class Application {
    //工厂方法类返回的是一个接口类
    abstract Product getProduct();
}

//子类继承了抽象类子类必须实现抽象类里的方法
class CreateProductA extends Application{
    @Override
    Product getProduct() {
        //ProductA实现了Product接口所以可以把创建的ProductA用Product接收
        return new ProductA();
    }
}

//子类继承了抽象类子类必须实现抽象类里的方法
class CreateProductB extends Application{
    @Override
    Product getProduct() {
        return new ProductB();
    }
}

三.抽象工厂模式

Abstract Factory提供一个创建一系列相关或相互依赖对象的接口而无需指定他们具体的类。

应用场景

程序需要处理不同序列的相关产品但是你不希望它依赖于这些产品的具体类时可是使用抽象工厂。

优点

1.可以确信你从工厂得到的产品彼此是兼容的;

2.可以避免具体产品和客户端代码之间的紧密耦合;

3.符合单一职责原则;

4.符合开闭原则。

public class AbstractFactory {
    public static void main(String[] args) {
        //创建一个类使用其实现的接口来接收
        IDataBaseUtils iDataBaseUtils = new MysqlDataBaseUtils();
        IConnection iConnection = iDataBaseUtils.getConnection();
        iConnection.connection();
        ICommand iCommand = iDataBaseUtils.getCommand();
        iCommand.command();
    }
}

interface IConnection{
    void connection();
}

interface ICommand{
    void command();
}

interface IDataBaseUtils{
    //包含一组的工厂方法
    IConnection getConnection();
    ICommand getCommand();
}

class MysqlConnection implements IConnection{
    @Override
    public void connection() {
        System.out.println("mysql connection");
    }
}

class OracleConnection implements IConnection{
    @Override
    public void connection() {
        System.out.println("oracle connection");
    }
}

class MysqlCommand implements ICommand{
    @Override
    public void command() {
        System.out.println("mysql command");
    }
}

class OracleCommand implements ICommand{
    @Override
    public void command() {
        System.out.println("oracle command");
    }
}

class MysqlDataBaseUtils implements IDataBaseUtils{
    @Override
    public IConnection getConnection() {
        return new MysqlConnection();
    }
    @Override
    public ICommand getCommand() {
        return new MysqlCommand();
    }
}

class OracleDataBaseUtils implements IDataBaseUtils{
    @Override
    public IConnection getConnection() {
        return new OracleConnection();
    }
    @Override
    public ICommand getCommand() {
        return new OracleCommand();
    }
}

四.建造者模式

将一个复杂对象的创建与他的标识分离使得同样的构建过程可以创建不同的表示

应用场景

1.需要生成的对象具有复杂的内部结构;

2.需要生成的对象内部属性本身相互依赖;

3.与不可变对象配合使用。

优点

1.建造者独立易扩展;

2.便于控制细节风险。

spring源码中的使用

1.org.springframework.web.servlet.mvc.method.RequestMappingInfo;

2.org.springframework.beans.factory.support.BeanDefinitionBuilder;

public class BuilderTest {

    public static void main(String[] args) {
        ProductBulider productBulider = new DefaultCreateBuilderProduct();
        Director director = new Director(productBulider);
        Product product = director.makeProduct("xxx", "1", "2", "3");
        System.out.println(product.toString());
    }
}

interface ProductBulider{
    void buliderProductName(String productName);
    void buliderPart1(String part1);
    void buliderPart2(String part2);
    void buliderPart3(String part3);
    Product bulid();
}

class Director{
    private ProductBulider productBulider;

    public Director(ProductBulider productBulider){
        this.productBulider = productBulider;
    }

    public Product makeProduct(String productName, String part1, String part2, String part3){
        productBulider.buliderProductName(productName);
        productBulider.buliderPart1(part1);
        productBulider.buliderPart2(part2);
        productBulider.buliderPart3(part3);
        Product product = productBulider.bulid();
        return product;
    }
}

class DefaultCreateBuilderProduct implements ProductBulider{
    private String productName;
    private String part1;
    private String part2;
    private String part3;

    @Override
    public void buliderProductName(String productName) {
        this.productName = productName;
    }

    @Override
    public void buliderPart1(String part1) {
        this.part1 = part1;
    }

    @Override
    public void buliderPart2(String part2) {
        this.part2 = part2;
    }

    @Override
    public void buliderPart3(String part3) {
        this.part3 = part3;
    }

    @Override
    public Product bulid() {
        return new Product( this.productName,  this.part1,  this.part2,  this.part3);
    }
}

class Product{
    private String productName;
    private String part1;
    private String part2;
    private String part3;

    public Product(){

    }

    public Product(String productName, String part1, String part2, String part3) {
        this.productName = productName;
        this.part1 = part1;
        this.part2 = part2;
        this.part3 = part3;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public String getPart1() {
        return part1;
    }

    public void setPart1(String part1) {
        this.part1 = part1;
    }

    public String getPart2() {
        return part2;
    }

    public void setPart2(String part2) {
        this.part2 = part2;
    }

    public String getPart3() {
        return part3;
    }

    public void setPart3(String part3) {
        this.part3 = part3;
    }

    @Override
    public String toString() {
        return "Product{" +
                "productName='" + productName + '\'' +
                ", part1='" + part1 + '\'' +
                ", part2='" + part2 + '\'' +
                ", part3='" + part3 + '\'' +
                '}';
    }
}

简化版的构造模式(内部静态类

public class BuilderTest {

    public static void main(String[] args) {
        Product product = new Product.ProductBuilder().productName("xxx").part1("1").part2("2").part3("3").bulid();
        System.out.println(product.toString());
    }
}


class Product{
    private final String productName;
    private final String part1;
    private final String part2;
    private final String part3;

    static class ProductBuilder{
        private  String productName;
        private  String part1;
        private  String part2;
        private  String part3;

        public ProductBuilder productName(String productName){
            this.productName = productName;
            return this;
        }

        public ProductBuilder part1(String part1){
            this.part1 = part1;
            return this;
        }

        public ProductBuilder part2(String part2){
            this.part2 = part2;
            return this;
        }

        public ProductBuilder part3(String part3){
            this.part3 = part3;
            return this;
        }

        Product bulid(){
            return new Product(this.productName,this.part1,this.part2,this.part3);
        }
    }

    public Product(String productName, String part1, String part2, String part3) {
        this.productName = productName;
        this.part1 = part1;
        this.part2 = part2;
        this.part3 = part3;
    }

    @Override
    public String toString() {
        return "Product{" +
                "productName='" + productName + '\'' +
                ", part1='" + part1 + '\'' +
                ", part2='" + part2 + '\'' +
                ", part3='" + part3 + '\'' +
                '}';
    }
}

五.原型模式

原型实例指定创建对象的种类并且通过拷贝这些原型创建新的对象。

应用场景

当代码不需要依赖于需要复制的对象的具体类时请使用Prototype模式。

优点

1.可以不耦合具体类的情况下克隆对象;

2.避免重复的初始化代码;

3.更方便的构建复杂对象。

Spring源码中的应用

1.org.springframework.beans.factory.support.AbstractBeanDefinition

2.java.util.Arrays

public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        BaseInfo baseInfo = new BaseInfo("1111");
        Product product = new Product("xx商品","part1","part2","part3",baseInfo);
        System.out.println(product.toString());
        Product clone = product.clone();
        System.out.println(clone.toString());
    }

}

class BaseInfo implements Cloneable{
    private String productId;

    public BaseInfo(String productId){
        this.productId = productId;
    }

    @Override
    protected BaseInfo clone() throws CloneNotSupportedException{
        BaseInfo baseInfo = (BaseInfo)super.clone();
        return baseInfo;
    }

    @Override
    public String toString() {
        return super.hashCode()+" ] BaseInfo{" +
                "productId='" + productId + '\'' +
                '}';
    }
}

class Product implements Cloneable{
    private String productName;
    private String part1;
    private String part2;
    private String part3;
    private BaseInfo baseInfo;

    @Override
    protected Product clone() throws CloneNotSupportedException{
        Product product = (Product)super.clone();
        BaseInfo baseInfo = (BaseInfo)product.baseInfo.clone();
        product.setBaseInfo(baseInfo);
        return product;
    }

    public Product(String productName, String part1, String part2, String part3,BaseInfo baseInfo) {
        this.productName = productName;
        this.part1 = part1;
        this.part2 = part2;
        this.part3 = part3;
        this.baseInfo = baseInfo;
    }

    @Override
    public String toString() {
        return super.hashCode()+"Product{" +
                "productName='" + productName + '\'' +
                ", part1='" + part1 + '\'' +
                ", part2='" + part2 + '\'' +
                ", part3='" + part3 + '\'' +
                ", baseInfo=" + baseInfo +
                '}';
    }

    public BaseInfo getBaseInfo() {
        return baseInfo;
    }

    public void setBaseInfo(BaseInfo baseInfo) {
        this.baseInfo = baseInfo;
    }
}

对一个对象的拷贝我们使实体实现Cloneable接口重写它的clone方法;若是实体里面引入了其它的实体例如上面的Product类中引入了BaseInfo类若是BaseInfo类没有实现Cloneable接口重写它的clone方法则对BaseInfo的拷贝是浅拷贝(类的hashcode相同

浅拷贝的问题时修改其中一个的BaseInfo值时另一个也会跟随着变化。

要达到深拷贝的程度我们需要让引入的BaseInfo也实现Cloneable接口重写它的clone方法在Product类中调用clone方法时调用下BaseInfo的clone来拷贝BaseInfo此时是深拷贝(类的hashcode不相同

六.享元模式

     享元模式运用共享技术有效的支持大量细粒度的对象。

优点

1.如果系统有大量类似的对象可以节省大量的内存及CUP资源

Spring源码中的运用

1.String、Integer、Long
2.com.sun.org.apache.bcel.internal.generic.InstructionConstants
public class FlyWeightTest {

    public static void main(String[] args) {
        //创建多个marker对象里面的参数BaseMessage相同时使用共享的方式
        Marker marker1 = new Marker(new BigDecimal(10),new BigDecimal(30),BaseMessageFactory.getBaseMessage("xx","xxxtip"));
        Marker marker2 = new Marker(new BigDecimal(60),new BigDecimal(80),BaseMessageFactory.getBaseMessage("xx","xxxtip"));
        System.out.println(marker1.toString());
        System.out.println(marker2.toString());
    }
}

class Marker{
    private BigDecimal lat;
    private BigDecimal lon;
    private BaseMessage baseMessage;

    public Marker(BigDecimal lat, BigDecimal lon, BaseMessage baseMessage) {
        this.lat = lat;
        this.lon = lon;
        this.baseMessage = baseMessage;
    }

    @Override
    public String toString() {
        return "Marker{" +
                "lat=" + lat +
                ", lon=" + lon +
                ", baseMessage=" + baseMessage.toString() +
                '}';
    }
}

class BaseMessageFactory{
    //使用map存放已经创建的对象供其他线程创建时复用
    private static Map<String,BaseMessage> map = new ConcurrentHashMap<String,BaseMessage>();
    public static BaseMessage getBaseMessage(String title,String tip){
        if(map.containsKey(title)){
            return map.get(title);
        }
        BaseMessage baseMessage = new BaseMessage(title,tip);
        map.put(title,baseMessage);
        return baseMessage;
    }
}


class BaseMessage{
    //字段使用final修饰创建后不可改变值
    private final String title;
    private final String tip;

    BaseMessage(String title, String tip) {
        System.out.println("create BaseMessage:"+title);
        this.title = title;
        this.tip = tip;
    }

    @Override
    public String toString() {
        return "BaseMessage{" +
                "title='" + title + '\'' +
                ", tip='" + tip + '\'' +
                '}';
    }
}

七.门面模式

    门面模式为子系统中的一组接口提供一个一致的接口Facade模式定义了一个高层接口这个接口使得这一子系统更加容易使用。

 应用场景

1.当需要使用复杂子系统的有限但直接的接口时请使用Facade模式。

2.当您想要将子系统组织成层时请使用Facade。

优点

1.简化客户端的调用。

源码中的经典应用

1.org.apache.catalina.connector.RequestFacade
public class FacadeTest {

    public static void main(String[] args) {
        Client1 client1 = new Client1();
        client1.pritlnSomething();
    }
}

//客户端1
class Client1{
    Facate facate = new Facate();

    public void pritlnSomething(){
        //使用门面模式来统一调用
        facate.printAll();
    }
}

//门面模式有facate来统一调用需要调用的方法
class Facate{
    SubMessage1 subMessage1 = new SubMessage1();
    SubMessage2 subMessage2 = new SubMessage2();
    SubMessage3 subMessage3 = new SubMessage3();

    public void printAll(){
        subMessage1.printSub1();
        subMessage2.printSub2();
        subMessage3.printSub3();
    }
}

//子类
class SubMessage1{
    public void printSub1(){
        System.out.println("printSub1...");
    }
}

class SubMessage2{
    public void printSub2(){
        System.out.println("printSub2...");
    }
}

class SubMessage3{
    public void printSub3(){
        System.out.println("printSub3...");
    }
}

八.适配器模式

    适配器模式将一个类的接口转换成客户希望的另一个接口Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

应用场景

1.当你希望使用某些现有类但其接口与你的其它代码不兼容时请使用适配器类。

2.当你希望重用几个现有的子类这些子类缺少一些不能添加到超类中的公共功能时请使用该模式。

优点

1.符合单一职责原则。

2.符合开闭原则。

JDK & Spring源码中的应用

JDK:
1.java.util.Arrays # asList()
2.java.util.Collections # list()
Spring:
1.org.springframework.context.event.GenericApplicationListenerAdapter
Object形式的适配器模式(注入类的方式:
public class AdapterObject {

    public static void main(String[] args) {
        Target target = new Adapter(new Adaptee());
        System.out.println(target.adapter10v());
    }
}

interface Target{
    int adapter10v();
}

class Adapter implements Target{

    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public int adapter10v() {
        int i = adaptee.adapter220v();
        //经过处理输出10V的电压
        int j = i/22;
        System.out.println(String.format("原电压  %d  v   转化后电压   %d  v",i,j));
        return j;
    }
}

//提供220V电压的类
class Adaptee{
    public int adapter220v(){
        return 220;
    }
}
Class形式的适配器模式(继承类的方式
public class AdapterClassDemo {

    public static void main(String[] args) {
        TargetClass targetClass = new AdapterClass();
        System.out.println(targetClass.adapter10v());
    }
}

interface TargetClass{
    int adapter10v();
}

//使用类继承的方式
class AdapterClass extends AdapteeClass implements TargetClass{

    @Override
    public int adapter10v() {
        int i = adapter220v();
        int j = i /22;
        System.out.println(String.format("原电压  %d  v   转化后电压   %d  v",i,j));
        return j;
    }
}


class AdapteeClass{
    public int adapter220v(){
        return 220;
    }
}

九.装饰者模式

      装饰者模式Decorator在不改变原有对象的基础上将功能附加到对象上。

应用场景

1.扩展一个类的功能或给一个类添加附加功能。

优点

1.不改变原有对象的情况下给一个对象扩展功能。

2.使用不同的组合可以实现不同的效果。

3.符合开闭原则(对扩展开放对修改关闭。

经典案例

1.javax.servlet.http.HttpServletRequest
2.javax.servlet.http.HttpServletResponse
public class DecoratorTest {
    public static void main(String[] args) {
        //这是一开始既有的实现
        /*Component component = new CreateComponent();
        component.operation();*/
        //使用接口接收创建的类;创建具体类的实现作为它实现的接口此接口是一个参数即可在不改变原有对象的基础上扩展附加一些属性
        Component component = new CreateDecorator2(new CreateDecoator1(new CreateComponent()));
        component.operation();
    }
}

interface Component{
    void operation();
}

class CreateComponent implements Component{
    @Override
    public void operation() {
        System.out.println("拍照");
    }
}

//抽象类实现接口可以不实现接口中的方法当子类继承此抽象类时再对接口中的方法进行实现
abstract class Decorator implements Component{
    Component component;

    public Decorator(Component component){
        this.component = component;
    }
}

//子类继承抽象父类需要实现父类未实现的接口方法需要调用父类的定义的构造函数
class CreateDecoator1 extends Decorator{

    //构造父类的构造方法
    public CreateDecoator1(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        System.out.println("美颜");
        //调用创建CreateDecoator1类时传递到父抽象类Decorator的component
        component.operation();
    }
}

class CreateDecorator2 extends Decorator{

    public CreateDecorator2(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        System.out.println("滤镜");
        component.operation();
    }
}

十.策略模式

     策略模式Stragety定义了算法族分别封装起来让它们直接可以互相替换此模式的变化独立于算法的使用者。

应用场景

1.业务代码需要根据场景不同切换不同的实现逻辑。

2.代码中存在大量if - else判断。

优点

1.符合开闭原则。

2.避免使用多重条件转移语句例if - else 语句、switch语句。

3.可以提高算法的安全性和保密性。

经典案例

1.java.util.Arrays # sort(T[] a, Comparator<? super T> c)
2.org.springframework.beans.factory.support.InstantiationStrategy
public class StrategyTest {

    public static void main(String[] args) {
        Zombie zombie = new NormalZombie(new OneStepMove(),new OneAttack());
        zombie.display();
        zombie.move();
        zombie.attack();
        //根据传入的值改变对应的方法调用输出的结果
        zombie.setMoveable(new TenStepMove());
        zombie.setAttackable(new TenAttack());
        System.out.println("......进过策略模式传递对象改变后调用同样的方法输出结果......");
        zombie.move();
        zombie.attack();
    }
}

//移动的接口
interface Moveable{
    void move();
}
//攻击的接口
interface Attackable{
    void attack();
}

//定义一个抽象类
abstract class Zombie {
    abstract void display();
    Moveable moveable;
    Attackable attackable;
    abstract void move();
    abstract void attack();

    public Zombie(Moveable moveable, Attackable attackable) {
        this.moveable = moveable;
        this.attackable = attackable;
    }

    public void setMoveable(Moveable moveable) {
        this.moveable = moveable;
    }

    public void setAttackable(Attackable attackable) {
        this.attackable = attackable;
    }
}

//子类继承抽象类
class NormalZombie extends Zombie{

    public NormalZombie(Moveable moveable, Attackable attackable) {
        super(moveable, attackable);
    }

    @Override
    void display() {
        System.out.println("普通类");
    }

    @Override
    void move() {
        moveable.move();
    }

    @Override
    void attack() {
        attackable.attack();
    }
}

//子类继承抽象类
class StyleZombie extends Zombie{

    public StyleZombie(Moveable moveable, Attackable attackable) {
        super(moveable, attackable);
    }

    @Override
    void display() {
        System.out.println("风格类......");
    }

    @Override
    void move() {
        moveable.move();
    }

    @Override
    void attack() {
        attackable.attack();
    }
}

//定义类实现具体的移动方法
class OneStepMove implements Moveable{
    @Override
    public void move() {
        System.out.println("走一步");
    }
}

class TenStepMove implements Moveable{
    @Override
    public void move() {
        System.out.println("走十步");
    }
}

class OneAttack implements Attackable{
    @Override
    public void attack() {
        System.out.println("一次攻击");
    }
}

class TenAttack implements Attackable{
    @Override
    public void attack() {
        System.out.println("十次攻击");
    }
}

程序执行输出结果值

十一.模板方法模式

      模板方法模式Template Method定义一个操作的算法骨架而将一些步骤延迟到子类中使得子类可以不改变一个算法的结构即可重定义改算法的某些特定步骤。

应用场景

1.一次性实现一个算法不变的部分并将可变部分留给子类实现。

2.各个子类中公共部分被提取出来集中到一个公共的父类中避免代码重复。

优点

1.提高代码复用性将相同部分代码放到抽象的父类中;

2.提供扩展性将不同的代码放到不同的子类中通过对子类的扩展增加新的行为;

3.符合开闭原则通过父类调用子类的操作通过对子类的扩展来增加新的行为。

Servlet Api & Spring源码

//service中定义了doGet/doPost等方法具体的实现由子类进行
1.javax.servlet.http.HttpServlet #service()

//handleRequest中定义了ModelAndView返回值具体的实现由子类进行
2.org.springframework.web.servlet.mvc.AbstractController #handleRequest()
public class TemplateTest {

    public static void main(String[] args) {
        AbstraceClass abstraceClass = new SubClass2();
        abstraceClass.operator();
    }
}

/**
 * 抽象父类
 */
abstract class AbstraceClass{
    //一般此方法是默认调用的方法
    public void operator(){
        System.out.println("准备");
        System.out.println("处理");
        //调用模板方法此方法由子类实现
        templateMethod();
    }

    protected abstract void templateMethod();
}

class SubClass1 extends AbstraceClass{
    //重写父类定义的抽象方法
    @Override
    protected void templateMethod() {
        System.out.println("子类1实现的方法");
    }
}

class SubClass2 extends AbstraceClass{
    //重写父类定义的抽象方法
    @Override
    protected void templateMethod() {
        System.out.println("子类2实现的方法");
    }
}

十二.观察者模式

    观察者模式Observer定义了对象之间的一对多依赖让多个观察者对象同时监听某一个主题对象当主题对象发生变化时它的所有依赖者都会收到通知并更新。

应用场景

1.当更改一个对象的状态可能需要更改其它对象并且实际的对象集事先未知或动态更改时请使用观察者模式。

优点

1.符合开闭原则;

2.可以在运行时建立对象之间的关系。

JDK & Spring源码中的应用

//定义了存放观察者的集合、添加、删除、通知观察者update的方法
1.java.util.Observable 

//定义了onApplicationEvent通知方法消息的发布在ApplicationEventMulticaster中由multicastEvent方法获取getApplicationListeners()注册的监听集合遍历此集合调用通知方法
2.org.springframework.context.ApplicationListener
public class ObserverTest {
    public static void main(String[] args) {
        Subject subject = new Subject();
        Observer subClass1 = new SubClass1();
        Observer subClass2 = new SubClass2();
        //把观察者对象添加进依赖的对象里面
        subject.add(subClass1);
        subject.add(subClass2);
        subject.notityAll("数据有更新了...");
        System.out.println("...移出某个需要通知的对象后...");
        subject.remove(subClass1);
        subject.notityAll("数据再次更新了...");
    }
}

class Subject {
    List<Observer> list = new ArrayList<Observer>();

    //添加需要通知的对象
    public void add(Observer observer){
        if(!list.contains(observer)){
            list.add(observer);
        }
    }

    //移出需要通知的对象
    public void remove(Observer observer){
        list.remove(observer);
    }

    //有变动通知所有的监听对象
    public void notityAll(Object object){
        for(int i = 0;i < list.size();i++){
            Observer observer = list.get(i);
            observer.notity(object);
        }
    }
}

interface Observer{
    void notity(Object object);
}

class SubClass1 implements Observer{
    @Override
    public void notity(Object object) {
        System.out.println("通知消息1"+object);
    }
}

class SubClass2 implements Observer{
    @Override
    public void notity(Object object) {
        System.out.println("通知消息2"+object);
    }
}

十三.责任链模式

     责任链模式Chain Of Responsibility 为请求创建了一个接收者对象的链。

应用场景

1.一个请求的处理需要多个对象当中的一个或几个协作处理。

优点

1.请求的发送者和接受者解耦;

2.可以控制执行顺序;

3.符合开闭原则和单一职责原则。

经典案例

//doFilter方法里面有一个FilterChain责任链
1.javax.servlet.Filter #doFilter()
2.javax.servlet.FilterChain #doFilter()
//sentinel中进行流控、熔断的策略就是使用的责任链模式使用8中插槽slot的方式判断是否达到某种限制达到则抛出对应的异常触发对应的控制
3.com.alibaba.csp.sentinel.CtSph #lookProcessChain()
public class ChainOfResponsibilityTest {
    public static void main(String[] args) {
        //通过构建者模式创建request
        Request request = new Request.RequestBuilder().isLogin(false).isEnter(false).bulid();
        //定义责任链LoginHandler的next为EnterHandlerEnterHandler的next为null
        Handler handler = new LoginHandler(new EnterHandler(null));
        boolean process = handler.process(request);
        if(process){
            System.out.println("校验通过");
        } else {
            System.out.println("校验不通过");
        }
    }
}

//定义一个请求类
class Request {
    private boolean isLogin;
    private boolean isEnter;

    public Request(boolean isLogin, boolean isEnter) {
        this.isLogin = isLogin;
        this.isEnter = isEnter;
    }

    //使用建造者模式创建
    static class RequestBuilder{
        private boolean isLogin;
        private boolean isEnter;

        RequestBuilder isLogin(boolean isLogin){
            this.isLogin = isLogin;
            return this;
        }
        
        RequestBuilder isEnter(boolean isEnter){
            this.isEnter = isEnter;
            return this;
        }
        
        Request bulid(){
            Request request = new Request(isLogin,isEnter);
            return request;
        }
    }

    public boolean isLogin() {
        return isLogin;
    }

    public boolean isEnter() {
        return isEnter;
    }
}

//定义一个抽象父类
abstract class Handler{
    Handler next;
    abstract boolean process(Request request);

    public Handler(Handler next) {
        this.next = next;
    }

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }
}

//定义子类
class LoginHandler extends Handler{

    //定义next的值
    public LoginHandler(Handler next) {
        super(next);
    }

    @Override
    boolean process(Request request) {
        System.out.println("登陆校验");
        if(request.isLogin()){
            Handler next = getNext();
            if(null == next){
                return true;
            }
            if(next.process(request)){
                return true;
            }
        }
        return false;
    }
}

//定义子类
class EnterHandler extends Handler{

    public EnterHandler(Handler next) {
        super(next);
    }

    @Override
    boolean process(Request request) {
        System.out.println("进入处理");
        if(request.isEnter()){
            Handler next = getNext();
            if(null == next){
                return true;
            }
            if(next.process(request)){
                return true;
            }
        }
        return false;
    }
}

十四.代理模式

    代理模式proxy代理对象具备真实对象的功能并代替真实对象完成相应操作并能够在操作执行前后对操作进行增强处理。

应用场景

1.日志的采集;

2.实现aop;

3.Rpc远程接口调用。

优点

1.在不修改目标对象的前提下能通过代理对象对目标对象进行扩

①静态代理

     需要定义接口或者父类代理对象和被代理对象需要实现相同的接口或者继承相同的父类在代理对象中注入被代理类通过代理对象调用真实的对象。

案例

public class StaticProxyTest {
    public static void main(String[] args) {
       RentHouse rentHouse = new ProxyRent(new RealRent());
       rentHouse.rent();
    }
}

//定义一个接口类
interface RentHouse{
    void rent();
}

//定义一个真实类
class RealRent implements RentHouse{
    @Override
    public void rent() {
        System.out.println("房东租房");
    }
}

//定义一个代理类代理类和真实类需要实现相同的接口
class ProxyRent implements RentHouse{
    //代理类需要注入真实的被代理类
    private RealRent realRent;
    public ProxyRent(RealRent realRent) {
        this.realRent = realRent;
    }

    @Override
    public void rent() {
        //在调用被代理类之前代理类可以添加一些其他的步骤
        System.out.println("带客户看房");
        //调用被代理类的方法
        realRent.rent();
        //在调用被代理类之后代理类可以添加一些其他的步骤
        System.out.println("签订合同");
    }
}

②jdk动态代理

      jdk动态代理涉及到java.lang.reflect.InvocationHandler和Proxy类实现InvocationHandler接口后重写invoke执行代理类的方法;使用Proxy的newProxyInstanse创建代理类需要的参数为接口类所以jdk动态代理需要使用接口类来接收源码方法如下

  //jdk创建代理类需要使用interfaces接口作为参数
  public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

案例

public class JdkDynamicProxyTest {
    public static void main(String[] args) {
        //jdk1.8及之前的版本设置保持jdk代理文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //jkd1.8之后的版本设置保持jdk代理文件
        //System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        JdkDynamicProxy proxy = new JdkDynamicProxy(new Cat("小猫"));
        Animal animal = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),new Class[]{Animal.class},proxy);
        animal.getUp();
        animal.sleep();

        proxy = new JdkDynamicProxy(new Student("学生"));
        Person person = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),new Class[]{Person.class},proxy);
        person.getUp();
        person.sleep();
    }
}

//定义一个动物的接口
interface Animal{
    //起床的方法
    void getUp();
    //睡觉的方法
    void sleep();
}

//定义一个人的接口
interface Person{
    //起床的方法
    void getUp();
    //睡觉的方法
    void sleep();
}

//定义类实现接口
class Cat implements Animal{
    private String name;

    public Cat(String name) {
        this.name = name;
    }

    @Override
    public void getUp() {
        System.out.println("动物"+name+"起床");
    }

    @Override
    public void sleep() {
        System.out.println("动物"+name+"睡觉");
    }
}

//定义接口实现类
class Student implements Person{

    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void getUp() {
        System.out.println("人类"+name+"起床");
    }

    @Override
    public void sleep() {
        System.out.println("人类"+name+"睡觉");
    }
}

//jdk动态代理通过实现InvocationHandler重写invoke方法
class JdkDynamicProxy implements InvocationHandler {
    //需要注入需要代理的类
    private Object bean;

    public JdkDynamicProxy(Object bean) {
        this.bean = bean;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //再调用代理类之前做一些前置处理
        String name = method.getName();
        if("getUp".equals(name)){
            System.out.println("早上好");
        } else if("sleep".equals(name)){
            System.out.println("晚安");
        }
        //执行被代理类的方法
        return method.invoke(bean,args);
    }


}

    可以通过System.getProperties().put来设置生成代理类的class文件可以在invoke调用真实类之前附加一些处理需要使用接口来接收代理类生成的代理类继承自Proxy实现的接口为创建代理类时传入的接口类里面有接口类定义的方法。

 ③Cglib动态代理

      Cglib是一个机遇ASM字节码生成库它允许在运行时对字节码进行修改和动态生成cglib生成的是真实类的子类。主要使用到org.springframework.cglib.proxy.MethodInterceptor和Enhancer类代理类实现MethodInterceptor接口重写invoke调用代理类的方法使用Enhancer字节码增强器来创界代理类。

案例

public class CglibDynamicProxyTest {
    public static void main(String[] args) {
        //输出生成的代理类
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\aop");
        CglibDynamicPorxy cglibDynamicPorxy = new CglibDynamicPorxy(new CatCglib("小猫"));
        CatCglib catCglib = (CatCglib) cglibDynamicPorxy.getProxy();
        catCglib.getUp();
        catCglib.sleep();

        cglibDynamicPorxy = new CglibDynamicPorxy(new StudentCglib("学生"));
        StudentCglib studentCglib = (StudentCglib) cglibDynamicPorxy.getProxy();
        studentCglib.getUp();
        studentCglib.sleep();
    }
}

//创建代理类
class CglibDynamicPorxy implements MethodInterceptor {
    //注入需要代理的类
    Object bean;

    public CglibDynamicPorxy(Object bean) {
        this.bean = bean;
    }

    //字节码增强器为无接口的类创建代理
    private Enhancer enhancer = new Enhancer();

    public Object getProxy(){
        //设置父类
        enhancer.setSuperclass(bean.getClass());
        //设置方法的回调
        enhancer.setCallback(this);
        //创建代理-子类继承自父类
        return enhancer.create();
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String name = method.getName();
        if("getUp".equals(name)){
            System.out.println("早上好");
        } else if("sleep".equals(name)){
            System.out.println("晚上好");
        }
        return method.invoke(bean,objects);
    }
}


//定义类实现接口
class CatCglib {
    private String name;

    public CatCglib() {
    }

    public CatCglib(String name) {
        this.name = name;
    }
    public void getUp() {
        System.out.println("动物"+name+"起床");
    }
    public void sleep() {
        System.out.println("动物"+name+"睡觉");
    }
}

//定义类
class StudentCglib{
    private String name;

    public StudentCglib() {
    }

    public StudentCglib(String name) {
        this.name = name;
    }
    public void getUp() {
        System.out.println("人类"+name+"起床");
    }
    public void sleep() {
        System.out.println("人类"+name+"睡觉");
    }
}

    可以通过System.setProperty来设置生成代理类的class文件地址可以在invoke调用真实类之前附加一些处理需要使用类来接收代理类生成的代理类继承自真实类实现的接口为Factory里面有类定义的方法相当于把真实类clone克隆了一份作为代理子类代理类中有clone方法。

十五.桥接模式

     桥接模式Bridge将抽象和实现分离使它们可以独立变化它是用组合关系代替继承关系来实现从而降低了抽象和实现这两个可变维度的耦合度。

应用场景

1.当一个类存在两个独立变化的维度且这两个维度都需要进行扩展时;

2.当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时;

3.当一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性时。

优点

1.抽象和实现分离扩展能力强;

2.符合开闭原则;

3.符合合成复用原则。

public class BridgeTest {
    public static void main(String[] args) {
        //创建实现化角色
        Animal animal = new Cat();
        //实现化角色通过创建抽象子类时注入进去;通过创建的子类进行桥接使其可以调用到实现化角色
        Behavior behavior = new SubBehavior1(animal);
        behavior.wakeUp();
        //也可以使用其他组合
        behavior = new SubBehavior2(new Sheep());
        behavior.wakeUp();
    }
}

//定义接口-实现化角色
interface Animal{
    void operation();
}

//具体实现化角色
class Cat implements Animal{
    @Override
    public void operation() {
        System.out.println("小猫...");
    }
}

//具体实现化角色
class Sheep implements Animal{
    @Override
    public void operation() {
        System.out.println("山羊");
    }
}

//定义抽象化角色
abstract class Behavior{
    //注入实现化角色
    Animal animal;

    public Behavior(Animal animal) {
        this.animal = animal;
    }

    abstract public void wakeUp();
}

//扩展抽象化角色--桥接
class SubBehavior1 extends Behavior{
    public SubBehavior1(Animal animal) {
        super(animal);
    }

    @Override
    public void wakeUp() {
        System.out.println("扩展抽象化1调用wakeUp");
        animal.operation();
    }
}

//扩展抽象化角色--桥接
class SubBehavior2 extends Behavior{
    public SubBehavior2(Animal animal) {
        super(animal);
    }

    @Override
    public void wakeUp() {
        System.out.println("扩展抽象化2调用wakeUp");
        animal.operation();
    }
}

十六.组合模式

     组合模式Composite有时候又叫做整体-部分模式它是一种将对象组合成树状的层次结构模式用来表示整体-部分的关系是用户对单个对象和组合对象有一致的访问性属于结构形设计模式。它将对象组织到树形结构中顶层的节点被称为根节点根节点下面可以包含树枝节点和叶子节点树枝节点下面又可以包含树枝节点和叶子节点树形结构图如下

应用场景

1.在需要表示一个对象整体与部分的层次结构的场合;

2.要求对用户隐藏组合对象与单个对象的不同用户可以用统一的接口使用组合结构中的所有对象的场合。

优点

1.组合模式使得客户端代码可以一致的处理当个对象和组合对象无须关心自己处理的是单个对象还是组合对象简化了客户端代码;

2.更容易在组合体内加入新的对象客户端不会因为加入了新的对象而改变源代码满足开闭原则。

①透明方式

      在该方式中由于抽象构件声明了所有子类中的方法所以客户端无须区别树叶对象和树枝对象对客户端来说是透明的。但其缺点是树叶构件中没有add(、remove(、getChild(方法却要实现他们(空实现或抛异常这样会带来一些安全性问题。

例如使用组合模式组织这样的数型图

public class TransparentCompositeTest {
    public static void main(String[] args) {
        Component composite0 = new Composite();
        Component composite1 = new Composite();
        Component left1 = new Leaf("1");
        Component left2 = new Leaf("2");
        Component left3 = new Leaf("3");
        composite0.add(left1);
        composite0.add(composite1);
        composite1.add(left2);
        composite1.add(left3);
        composite0.operate();
    }
}

//抽象构件-定义子类需要的所有方法
interface Component{
    void add(Component component);
    void remove(Component component);
    Component getChild(int index);
    void operate();
}

//树叶构件-没有添加、删除、获取子类的方法实现
class Leaf implements Component{

    private String name;

    public Leaf(String name) {
        this.name = name;
    }

    @Override
    public void add(Component component) {

    }

    @Override
    public void remove(Component component) {

    }

    @Override
    public Component getChild(int index) {
       return null;
    }

    @Override
    public void operate() {
        System.out.println("叶子"+name+"被访问");
    }
}

//树枝构件-包含它下面的子类集合
class Composite implements Component{

    private List<Component> childList = new ArrayList<Component>();

    @Override
    public void add(Component component) {
        childList.add(component);
    }

    @Override
    public void remove(Component component) {
       childList.remove(component);
    }

    @Override
    public Component getChild(int index) {
       return childList.get(index);
    }

    @Override
    public void operate() {
        for(Component component : childList){
            component.operate();
        }
    }
}

 ②安全方式

       在该方式中将管理子构件的方法放到树枝构件中抽象构件和树叶构件没有对子对象的管理方法这样就避免了透明方式的安全性问题但由于叶子和树枝有不同的接口客户端在调用时要知道树叶对象和树枝对象的存在所以失去了透明性。

public class SafeCompositeTest {
    public static void main(String[] args) {
        CompositeSafe compositeSafe0 = new CompositeSafe();
        CompositeSafe compositeSafe1 = new CompositeSafe();
        ComponentSafe leaf1 = new LeafSafe("1");
        ComponentSafe leaf2 = new LeafSafe("2");
        ComponentSafe leaf3 = new LeafSafe("3");
        compositeSafe0.add(leaf1);
        compositeSafe0.add(compositeSafe1);
        compositeSafe1.add(leaf2);
        compositeSafe1.add(leaf3);
        compositeSafe0.operate();
    }
}

//抽象构件-只定义公共的方法
interface ComponentSafe{
    void operate();
}

//树叶构件
class LeafSafe implements ComponentSafe{
    private String name;

    public LeafSafe(String name) {
        this.name = name;
    }

    @Override
    public void operate() {
        System.out.println("叶子"+name+"被调用");
    }
}

//树枝构建
class CompositeSafe implements ComponentSafe{

    private List<ComponentSafe> childList = new ArrayList<ComponentSafe>();

    public void add(ComponentSafe componentSafe){
        childList.add(componentSafe);
    }

    public void remove(ComponentSafe componentSafe){
        childList.remove(componentSafe);
    }

    public ComponentSafe getChild(int index){
        return childList.get(index);
    }

    @Override
    public void operate() {
        for(ComponentSafe componentSafe : childList){
            componentSafe.operate();
        }
    }
}

十七.命令模式

     命令模式Command将一个请求封装为一个对象使发出请求的责任和执行请求的责任分割开这样两者之间通过命令对象进行沟通这样方便将命令对象进行存储、传递、调用、增加和管理。

应用场景

1.请求调用者需要和请求接收者解耦时命令模式可以使调用者和接收者不直接交互;

2.系统随机请求命令或经常增加、删除命令时命令模式可以方便的实现这些功能;

3.当系统需要支持命令的撤销(Undo操作和恢复(Redo操作时可以将命令对象存储起来采用备忘录模式来实现。

优点

1.通过引入中间件(抽象接口降低系统的耦合度;

2.扩展性良好增加或删除命令非常方便采用命令模式增加或删除命令不会影响其他类且满足开闭原则;

3.可以实现宏命令命令模式可以与组合模式结合将多个命令装配成一个组合命令即宏命令;

4.方便实现Undo和Redo操作命令模式可以与备忘录模式结合使用实现命令的撤销和恢复;

5.可以在现有命令的基础上增加而外功能例如日志记录。

public class CommandTest {
    public static void main(String[] args) {
        //创建翻上一个视频的命令对象
        Command upVideoCommand = new UpVideoCommand();
        //创建关闭电视机的命令对象
        Command closeVideoCommand = new CloseVideoCommand();
        //创建调用者
        ControllerInvoker controllerInvoker = new ControllerInvoker();
        //把可以调用的命令设置到调用者中
        controllerInvoker.setUpVideoCommand(upVideoCommand);
        controllerInvoker.setCloseVideoCommand(closeVideoCommand);
        //调用者调用方法-翻上一个视频
        controllerInvoker.upVideo();
        //调用者调用方法-关闭电视机
        controllerInvoker.closeVideo();
    }
}

//抽象命令类
interface Command{
    void execute();
}

//具体命令类-翻上一个视频操作
class UpVideoCommand implements Command{
    //注入此命令的接收者
    private VideoTopReceiver videoTopReceiver;

    public UpVideoCommand() {
        videoTopReceiver = new VideoTopReceiver();
    }

    @Override
    public void execute() {
        System.out.println("按了翻上一个视频的按钮");
        //给接收者发送命令
        videoTopReceiver.upVideo();
    }
}

//具体命令类-关闭电视机
class CloseVideoCommand implements Command{
    //注入此命令的接收者
    private VideoReceiver videoReceiver;

    public CloseVideoCommand() {
        videoReceiver = new VideoReceiver();
    }

    @Override
    public void execute() {
        System.out.println("按了关机的按钮");
        //给接收者发送命令
        videoReceiver.closeVideo();
    }
}

//命令实现者-电视机顶盒
class VideoTopReceiver {
    public void upVideo(){
        System.out.println("收到命令翻上一个台");
    }
}

//命令实现者-电视机
class VideoReceiver{
    public void closeVideo(){
        System.out.println("收到命令电视机关机");
    }
}

//调用者-遥控器设置了可以调用的命令
class ControllerInvoker{
    //定义好有哪些命令可以调用
    private Command upVideoCommand,closeVideoCommand;

    public void setUpVideoCommand(Command upVideoCommand) {
        this.upVideoCommand = upVideoCommand;
    }

    public void setCloseVideoCommand(Command closeVideoCommand) {
        this.closeVideoCommand = closeVideoCommand;
    }

    //当按下调用上一个节目的按钮执行的方法
    public void upVideo(){
        upVideoCommand.execute();
    }

    //当按电视关机的按钮执行的方法
    public void closeVideo(){
        closeVideoCommand.execute();
    }
}

十八.状态模式

      状态模式State对有状态的对象把复杂的判断逻辑提取到不同的状态对象中允许状态对象在其内部状态发生改变时改变其行为。

应用场景
1.当一个对象的行为取决于它的状态并且它必须在运行时根据状态改变它的行为时就可以考虑使用状态模式;

2.一个操作中含有庞大的分支结构并且这些分支决定于对象的状态时。

优点

1.结构清晰状态模式将与特定状态相关的行为局部化到一个状态中并且将不同状态的行为分隔开来满足单一职责原则;

2.将状态转换化减少对象间的相互依赖将不同的状态引入独立的对象中会使得状态转换变得更加明确且减少对象间的相互依赖;

3.状态类职责明确有利于程序的扩展通过定义新的子类很容易的增加新的状态和转换。

例如线程的状态转换

public class StateTest {
    public static void main(String[] args) {
        ThreadContext threadContext = new ThreadContext();
        //启动线程方法执行前状态新建执行后状态变为就绪
        threadContext.start();
        //获取到cpu资源方法执行前状态就绪执行后状态变为运行
        threadContext.getCpu();
        //中断线程方法执行前状态运行执行后状态变为阻塞
        threadContext.suspend();
        //恢复线程方法执行前状态阻塞执行后状态变为就绪
        threadContext.resume();
        //获取到cpu资源方法执行前状态就绪执行后状态变为运行
        threadContext.getCpu();
        //停止线程 方法执行前状态运行执行后状态变为停止
        threadContext.stop();
    }
}

//环境类-存放全局的状态
class ThreadContext{
    //环境类里面放一个记录状态的类通过该变此对象的值来改变环境的状态
    ThreadState state;

    //创建环境类的时候先默认给一个初始的state状态
    public ThreadContext() {
        state = new New();
    }

    //程序运行过程中获取状态
    public ThreadState getState() {
        return state;
    }

    //程序运行过程中重新设置状态值
    public void setState(ThreadState state) {
        this.state = state;
    }

    //调用启动方法-状态为新建的时候
    public void start(){
        //把state抽象类强转成具体的子类调用子类的方法并把环境类传递过去这样可以在此方法调用后改变state状态值
        ((New)state).start(this);
    }

    //调用获取cpu资源-状态为就绪的时候
    public void getCpu(){
        //把state抽象类强转成具体的子类调用子类的方法并把环境类传递过去这样可以在此方法调用后改变state状态值
        ((Runnable)state).getCpu(this);
    }

    //调用线程中断-状态为运行的时候
    public void suspend(){
        //把state抽象类强转成具体的子类调用子类的方法并把环境类传递过去这样可以在此方法调用后改变state状态值
        ((Running)state).suspend(this);
    }

    //调用线程结束-状态为运行的时候
    public void stop(){
        //把state抽象类强转成具体的子类调用子类的方法并把环境类传递过去这样可以在此方法调用后改变state状态值
        ((Running)state).stop(this);
    }

    //调用线程结束-状态为阻塞的时候
    public void resume(){
        //把state抽象类强转成具体的子类调用子类的方法并把环境类传递过去这样可以在此方法调用后改变state状态值
        ((Blocked)state).resume(this);
    }
}

//抽象状态类
abstract class ThreadState{
    String stateName;
}

//具体状态类-线程新建状态可以调用启动方法
class New extends ThreadState{
    public New(){
        stateName = "新建状态";
        System.out.println("线程创建.");
    }

    public void start(ThreadContext threadContext){
        System.out.println("调用线程启动方法start()");
        if("新建状态".equals(stateName)){
            //重新设置环境类中state状态变量的值
            threadContext.setState(new Runnable());
        } else {
            System.out.println("线程没有处于新建状态不允许启动线程");
        }
    }
}

//具体实现类-线程就绪状态可以调用获取cpu资源的方法
class Runnable extends ThreadState{

    public Runnable() {
        stateName = "就绪状态";
        System.out.println("线程处于就绪状态");
    }

    public void getCpu(ThreadContext threadContext){
        System.out.println("调用线程获取资源方法getCpu()");
        if("就绪状态".equals(stateName)){
            //重新设置环境类中state状态变量的值
            threadContext.setState(new Running());
        } else {
            System.out.println("线程没有处于就绪状态不允许获取资源");
        }
    }
}

//具体实现类-线程运行状态可以调用中断、结束线程的方法
class Running extends ThreadState{

    public Running() {
        stateName = "运行状态";
        System.out.println("线程处于运行状态");
    }

    public void suspend(ThreadContext threadContext){
        System.out.println("调用线程中断方法suspend()");
        if("运行状态".equals(stateName)){
            //重新设置环境类中state状态变量的值
            threadContext.setState(new Blocked());
        } else {
            System.out.println("线程没有处于运行状态不允许中断");
        }
    }

    public void stop(ThreadContext threadContext){
        System.out.println("调用线程结束方法stop()");
        if("运行状态".equals(stateName)){
            //重新设置环境类中state状态变量的值
            threadContext.setState(new Stop());
        } else {
            System.out.println("线程没有处于运行状态不允许结束");
        }
    }
}

//具体实现类-线程阻塞状态可以调用恢复线程的方法
class Blocked extends ThreadState{

    public Blocked() {
        stateName = "阻塞状态";
        System.out.println("线程处于阻塞状态");
    }

    public void resume(ThreadContext threadContext){
        System.out.println("调用线程恢复方法resume()");
        if("阻塞状态".equals(stateName)){
            //重新设置环境类中state状态变量的值
            threadContext.setState(new Runnable());
        } else {
            System.out.println("线程没有处于阻塞状态不允许恢复");
        }
    }
}

//具体实现类-线程结束状态
class Stop extends ThreadState{

    public Stop() {
        stateName = "结束状态";
        System.out.println("线程处于结束状态");
    }
}

十九.中介者模式

     中介者模式Mediator定义一个中介对象来封装一系列对象之间的交互使原有对象之间的耦合松散且可以独立的改变他们之间的交互。

应用场景

1.当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时;

2.当想创建一个运行于多个类之间的对象又不想生成新的子类时。

优点

1.类之间各司其职符合迪米特法则;

2.降低了对象之间的耦合性使得对象易于独立的被复用;

3.将对象之间的一对多关联转变为一对一的关联提高系统的灵活性使得系统易于维护和扩展。

例如中介者结构图的实现

public class MediatorTest {
    public static void main(String[] args) {
        //创建中介者
        Mediator mediator = new ConcreteMediator();
        //创建同事类
        Colleague concreteColleague1 = new ConcreteColleague1();
        Colleague concreteColleague2 = new ConcreteColleague2();
        //把同事类添加到中介者中
        mediator.register(concreteColleague1);
        mediator.register(concreteColleague2);
        //同事类发送消息
        concreteColleague1.send();
        concreteColleague2.send();
    }
}

//抽象中介者
abstract class Mediator{
    //同事类添加到中介者中
    abstract void register(Colleague colleague);
    //转发消息
    abstract void relay(Colleague colleague);
}

//抽象同事类
abstract class Colleague{
    //记录此同事类关联的中介者
    Mediator mediator;
    //接收消息
    abstract void receive();
    //发送消息
    abstract void send();

    //设置此同事类关联的中介者
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }
}

//具体中介者
class ConcreteMediator extends Mediator{
    //记录注册在此中介者中的同事集合
    private List<Colleague> list = new ArrayList<Colleague>();

    @Override
    void register(Colleague colleague) {
        if(!list.contains(colleague)){
            //把同事类添加到它关联的中介者中
            list.add(colleague);
            //给此同事类设置它关联的中介者
            colleague.setMediator(this);
        }
    }

    @Override
    void relay(Colleague c) {
        for(Colleague colleague : list){
            //转发的同事不包含发消息的同事
            if(!c.equals(colleague)){
                colleague.receive();
            }
        }
    }
}

//具体同事类
class ConcreteColleague1 extends Colleague{

    @Override
    void receive() {
        System.out.println("具体同事类1收到消息");
    }

    @Override
    void send() {
        System.out.println("具体同事类1发送消息");
        //通过此同事类关联的中介者进行消息转发(不包含转发给自己
        mediator.relay(this);
    }
}

//具体同事类
class ConcreteColleague2 extends Colleague{

    @Override
    void receive() {
        System.out.println("具体同事类2收到消息");
    }

    @Override
    void send() {
        System.out.println("具体同事类2发送消息");
        //通过此同事类关联的中介者进行消息转发(不包含转发给自己
        mediator.relay(this);
    }

二十.迭代器模式

      迭代器模式Iterator提供一个对象来顺序访问聚合对象中的一系列数据而不暴露聚合对象的内部表示。

应用场景

1.当需要为聚合对象提供多种遍历方式时;

2.当需要为遍历不同的聚合结构提供一个统一的接口时;

3.当访问一个聚合对象的内容而无须暴露其内部细节的表示时。

优点

1.访问一个聚合对象的内容而无须暴露它的内部表示;

2.遍历任务交由迭代器完成这简化了聚合类;

3.它支持以不同方式遍历一个聚合甚至可以自定义迭代器的子类以支持新的遍历;

4.增加新的聚合类和迭代器类都很方便无须修改原有代码;

5.封装性良好为遍历不同的聚合结构提供一个统一的接口。

public class IteratorTest {

    public static void main(String[] args) {
        //创建聚合类
        Aggegate concreteAggegate = new ConcreteAggegate();
        //向聚合类中添加对象
        concreteAggegate.add("苹果");
        concreteAggegate.add("橘子");
        concreteAggegate.add("香蕉");
        concreteAggegate.add("芒果");
        //把聚合类中的集合对象作为参数传递到迭代器中创建迭代器
        Iterator iterator = concreteAggegate.getIterator();
        //遍历数据
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("遍历结束");
        System.out.println(iterator.first());
        System.out.println(iterator.hasNext());
        System.out.println(iterator.next());
        System.out.println(iterator.previous());
        System.out.println(iterator.last());
        System.out.println(iterator.hasNext());
    }
}

//聚合抽象类
interface Aggegate{
    //添加元素到集合中
    void add(Object object);
    //从集合中移出元素
    void remove(Object object);
    //获得迭代器
    Iterator getIterator();
}

//抽象迭代器类
interface Iterator{
    //获取第一个元素
    Object first();
    //获取下一个元素
    Object next();
    //获取前一个元素
    Object previous();
    //获取最后一个元素
    Object last();
    //是否还有下一个元素
    boolean hasNext();
}

//具体聚合类
class ConcreteAggegate implements Aggegate{
    //定义一个集合用于存放加入到聚合类中的对象
    private List<Object> list = new ArrayList<Object>();

    @Override
    public void add(Object object) {
        list.add(object);
    }

    @Override
    public void remove(Object object) {
        list.remove(object);
    }

    @Override
    public Iterator getIterator() {
        return new ConcreteIterator(list);
    }
}

//具体迭代器
class ConcreteIterator implements Iterator{
    //定义一个集合用于接收聚合类中的集合对象
    private List<Object> list = new ArrayList<Object>();
    //迭代器的索引
    int index = -1;

    public ConcreteIterator(List<Object> list) {
        this.list = list;
    }

    @Override
    public Object first() {
        index = 0;
        return list.get(index);
    }

    @Override
    public Object next() {
        if(this.hasNext()){
            return list.get(++index);
        }
        return null;
    }

    @Override
    public Object previous() {
        if(index > 0) {
            return list.get(--index);
        }else {
            return null;
        }
    }

    @Override
    public Object last() {
        index = list.size()-1;
        return list.get(index);
    }

    @Override
    public boolean hasNext() {
        if(index >= list.size()-1){
            return false;
        }
        return true;
    }
}

二十一.访问者模式

      访问者模式visitor将作用于某种数据结构中的各元素的操作分离出来分装成独立的类使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作为数据结构中的每个元素提供多种访问方式它将对数据的操作与数据结构进行分离。

应用场景

1.对象结构相对稳定但其操作算法经常变化的程序;

2.对象结构中的对象需要提供多种不同且不相关的操作而且要避免让这些操作的变化影响对象的结构。

3.对象结构包含很多类型的对象希望对这些对象实施一些依赖于其具体类型的操作。

优点

1.扩展性好能够在不修改对象结构中的元素的情况下为对象结构中的元素添加新的功能;

2.复用性好可以通过访问者来定义整个对象结构通用的功能从而提高系统的复用程度;

3.灵活性好访问者模式将数据结构和作用于结构上的操作解耦是的操作集合可相对自由的演化而不影响系统的数据结构;

4.符合单一职责原则访问者模式把相关的行为封装在一起构成一个访问者使每个访问者的功能都比较单一。

public class VisitorTest {
    public static void main(String[] args) {
        //创建结构对象
        ObjectStructure objectStructure = new ObjectStructure();
        //添加可以访问的元素
        ConcreteElements1 concreteElements1 = new ConcreteElements1();
        ConcreteElements2 concreteElements2 = new ConcreteElements2();
        objectStructure.add(concreteElements1);
        objectStructure.add(concreteElements2);
        //创建访问对象
        Visitor visitor = new ConcreteVisitor1();
        //结构对象接受visitor访问者的访问遍历结构对象中存的所有元素接受访问
        objectStructure.accept(visitor);
    }
}

//抽象访问者
interface Visitor{
    //访问哪个元素元素作为参数
    void visit(ConcreteElements1 elements);
    void visit(ConcreteElements2 elements);
}

//抽象元素
interface Elements{
    //接收谁的访问访问者作为参数传递进来
    void accept(Visitor vistor);
}

//具体访问者
class ConcreteVisitor1 implements Visitor{

    @Override
    public void visit(ConcreteElements1 elements) {
        System.out.print("具体访问者1访问-》");
        elements.operator1();
    }

    @Override
    public void visit(ConcreteElements2 elements) {
        System.out.print("具体访问者1访问-》");
        elements.operator2();
    }
}

//具体元素
class ConcreteElements1 implements Elements{

    //元素接收访问
    @Override
    public void accept(Visitor visitor) {
        //当前元素接受visitor的访问调用visitor的访问方法
        visitor.visit(this);
    }

    public void operator1(){
        System.out.println("元素1");
    }
}

//具体元素
class ConcreteElements2 implements Elements{

    //元素接收访问
    @Override
    public void accept(Visitor visitor) {
        //当前元素接受visitor的访问
        visitor.visit(this);
    }

    public void operator2(){
        System.out.println("元素2");
    }
}

//对象结构
class ObjectStructure{
    //存放有哪些元素可以访问
    List<Elements> list = new ArrayList<Elements>();

    //添加元素到集合
    public void add(Elements elements){
        list.add(elements);
    }

    //接受访问-接受谁的方法作为参数传递进来
    public void accept(Visitor visitor){
        Iterator<Elements> iterator = list.iterator();
        while(iterator.hasNext()){
            //让元素接受某个访问者的访问
            iterator.next().accept(visitor);
        }

    }

}

二十二.备忘录模式

       备忘录模式Memento在不破坏封装性的前提下捕获一个对象的内部状态并在改对象之外保存这个状态以便以后当需要时能将该对象恢复到原先保存的状态该模式又叫快照模式。

应用场景

1.需要保存与恢复数据的场景如玩游戏时的中间结果存档功能;

2.需要提供一个可回滚操作的场景如Word、记事本、Photoshop、Eclipse等软件在编辑时按Ctrl+Z组合键还有数据库中事务操作。

优点

1.提供了一种可以恢复状态的机制当用户需要时能够比较方便的将数据恢复到某个历史状态;

2.实现了内部状态的封装除了创建它的发起人之外其它对象都不能够访问这些状态信息;

3.简化了发起人类发起人不需要管理和保存其内部状态的各个备份所有状态信息都保存在备忘录中并由管理者进行管理这符合单一职责原则。

public class MementoTest {
    public static void main(String[] args) {
        //创建管理者
        Caretaker caretaker = new Caretaker();
        //创建发起者
        Originator originator = new Originator();
        originator.setState("0");
        //创建备份
        Memento memento = originator.createMemento();
        //备份添加到管理者中
        caretaker.push(memento);
        originator.setState("1");
        //备份添加到管理者中
        caretaker.push(originator.createMemento());
        originator.setState("2");
        System.out.println("当前状态值:"+originator.getState());
        //第一次还原
        originator.restoreMemento(caretaker.pop());
        System.out.println("第一次还原状态值:"+originator.getState());
        //第二次还原
        originator.restoreMemento(caretaker.pop());
        System.out.println("第二次还原状态值:"+originator.getState());
    }
}

//备忘录实体-需要记录发起人存放的所有字符值
class Memento{
    //字段与发起人实体中相同的字段
    private String state;

    public Memento(String state) {
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

//发起人角色
class Originator{
    private String state;

    //创建备份录
    public Memento createMemento(){
        //把需要备份的字段都传递到备份类实体中进行备份
        return new Memento(state);
    }

    //恢复备份-通过某个备份文件还原当前发起人的数据
    public void restoreMemento(Memento memento){
        //把备份类记录的值还原到发起人类对应的字段中
        this.state = memento.getState();
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
}

//管理者-记录着备份的对象
class Caretaker{
    //使用栈记录备份的记录栈的特性先进后出符合还原操作
    private Stack<Memento> stack = new Stack<Memento>();

    //添加备份到栈
    public void push(Memento memento) {
        stack.push(memento);
    }

    //还原时从栈中拿出备份的记录
    public Memento pop(){
        return stack.pop();
    }
}

二十三.解释器模式

      解释器模式Interpreter给分析对象定义一个语言并定义该语言的文法表示再设计一个解析器来解释语言中的句子。也就是说用编译语言的方式来分析应用中的实例这种模式实现了文法表达式处理的接口该接口解释一个特定的上下文。

应用场景

1.当语言的文法比较简单且执行效率不是关键问题时;

2.当问题重复出现且可以用一种简单的语言来进行表达时;

3.当一个语言需要解释执行并且语言中的句子可以表示为一个抽象语法树的时候。

优点

1.扩展性好由于在解释器模式中使用类来表示语言的文法规则因此可以通过继承等机制来改变或扩展文法;

2.容易实现在语法树中的每个表达式节点类都是相似的所以实现其文法较为简单。

public class InterpreterTest {
    public static void main(String[] args) {
        Context context = new Context();
        context.checkMes("军人的子女");
        context.checkMes("军人的妻子");
        context.checkMes("工人的子女");
        context.checkMes("警察的父母");
        context.checkMes("警察的朋友");
    }
}

//抽象表达式
interface AbstractExpression{
    //接收某个输入的信息
    boolean interprete(String info);
}

//终结者表达式-名词、代词
class TerminalExpression implements AbstractExpression{

    //定义集合存放允许的词
    private List<String> list = new ArrayList<String>();

    //创建对象时需要给出允许的词
    public TerminalExpression(String[] arrStr) {
        for(int i = 0;i < arrStr.length;i++){
            list.add(arrStr[i]);
        }
    }

    @Override
    public boolean interprete(String info) {
        //包含这个此返回true
        if(list.contains(info)){
            return true;
        }
        return false;
    }
}

//非终结者表达式-谓语(动词
class NonTerminalExpression implements AbstractExpression{
    //记录终结者表达式的对象
    private AbstractExpression jobExpression;
    private AbstractExpression persionExpression;

    public NonTerminalExpression(AbstractExpression jobExpression, AbstractExpression persionExpression) {
        this.jobExpression = jobExpression;
        this.persionExpression = persionExpression;
    }

    @Override
    public boolean interprete(String info) {
        //非终结者进行分词
        String[]  arr = info.split("的");
        //判断是否包含
        return jobExpression.interprete(arr[0]) && persionExpression.interprete(arr[1]);
    }
}

//环境角色
class Context{
    //定义允许的此
    String[] jobArr = {"军人","警察"};
    String[] persionArr = {"父母","子女"};

    //定义一个非终结表达式对象
    AbstractExpression nonTerminalExpression;

    public Context() {
        //创建终结者表达式对象
        TerminalExpression job = new TerminalExpression(jobArr);
        TerminalExpression persion = new TerminalExpression(persionArr);
        nonTerminalExpression = new NonTerminalExpression(job, persion);
    }

    //输入一个字符判断是否符合表达式
    public void checkMes(String info){
        boolean interprete = nonTerminalExpression.interprete(info);
        if(interprete){
            System.out.println(info+"可以享受优先的政策");
        } else {
            System.out.println(info+"正常排队");
        }
    }
}

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Java