Java设计模式在平时的开发中起到了至关重要的作用。设计模式的主要目的是:
1、降低耦合度,使得类的修改不至于“牵一发而动全身”。
2、提高可扩展性,新增功能对原有的代码没什么影响
3、提高可复用性,降低过多的使用类时,导致类爆炸的情况
4、提高灵活性,代码能够通过接口灵活调用
5、提高可维护性,修改的地方越少
1、单一原则:一个类只负责一个职责
2、开闭原则:对修改关闭,对扩展开放
3、里氏替换原则:不要破坏继承关系
4、接口隔离原则:暴露最小接口,避免接口过于臃肿
5、依赖倒置原则:面向抽象编程
6、迪米特 法则:尽量不跟陌生人讲话
7、合成复用原则:多使用组合、聚合、少用继承
一个方法 一个类只负责一个职责,各个职责的程序改动,不影响其它程序,实现 高内聚,低耦合
优点:降低耦合,提高可维护性,对一个类进行单独处理并且不影响其他类
对修改关闭,对扩展开放,核心是:抽象化,多态使用
优点:提高可扩展性,提高可维护性,提高可复用性
所有使用父类的地方,必须能够透明的使用子类对象
例如:父类Animal;子类Dog继承父类Animal,子类Cat继承父类Animal。
Animal animal=new Dog();
//同样可以透明的使用
Animal animal=new Cat();
当子类重写父类的方法时,则不适合使用里氏替换原则。
每一个接口承担独立的角色,只干自己该干的事情。
只暴露最小接口,实现类不需要用到实现的方法不要放在接口。
指的是面向抽象编程,对抽象类或接口进行依赖,比较灵活。
比如:有抽象类Animal,子类Dog继承父类Animal,子类Cat继承父类Animal。在依赖的时候用抽象类,在使用的时候指定子类
//抽象类和子类
abstract class Animal{
abstract void hello();
}
class Dog extends Animal{
@Override
void hello() {
System.out.println("hello ,I am dog");
}
}
class Cat extends Animal{
@Override
void hello() {
System.out.println("hello ,I am cat");
}
}
//依赖到抽象类
class Client{
Animal a;
public Client(Animal a){
this.a=a;
}
public void hello(){
a.hello();
}
}
//测试类进行使用
public class Test {
public static void main(String args[]) {
//在使用到Animal的使用,需要定义它的子类
Client c=new Client(new Dog());
c.hello();//打印指定的方法
}
}
尽量不要跟陌生人说话。
不是陌生人的情况:
目的:降低耦合,高内聚
尽量使用组合、聚合的方式,少使用继承。
原因:继承会导致耦合度变高。
聚合方式的使用案例:
class A{}
class Test{
A a;
public void useA(A a){
this.a=a;
}
}
组合方式的使用案例:
class A{}
class Test{
A a=new A();
}
组合和聚合的区别 : 组合方式在使用Test对象的时候会立即开辟A对象的空间,而聚合的方式是在使用到A对象的时候才会开辟A对象的空间。
特点:当需求是一个类只需要一个实例
单例模式有:1、饿汉模式;2、懒汉模式;3、双重检查模式;4、枚举模式
饿汉模式(推荐使用)
特点: 当类加载时创建好对象,并且在外部不能通过new创建该对象,只能调用这个类的的方法进行调用。线程安全,在实际开发中用的最多
案例:
方式一
/**
* 饿汉方式一
* @Author:小庄
*/
public class Singleton {
//private不允许外部调用new创建对象
private Singleton(){}
//使用静态关键字”static“保证只有一次
private static Singleton instance=new Singleton();
//外部可直接通过类进行调用静态方法
public static Singleton getInstance(){
return instance;
}
}
/**
* 饿汉方式二
* @Author:小庄
*/
class Singleton2 {
private static Singleton2 instance;
private Singleton2(){
instance=new Singleton2();
}
/**
* 饿汉方式二
* @Author:小庄
*/
class Singleton2 {
private static Singleton2 instance;
static {
instance=new Singleton2();
}
private Singleton2(){}
//外部可直接通过类进行调用静态方法
public static Singleton2 getInstance(){
return instance;
}
}
懒汉模式(不推荐使用)
特点: 等需要该类的时候再加载,会考虑线程安全问题
1、不安全的懒汉模式
/**
* 线程不安全的懒汉模式
* @Author:小庄
*/
class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
instance=new Singleton();
return instance;
}
}
class Singleton2{
private static Singleton2 instance;
private Singleton2(){}
public static Singleton2 getInstance(){
if(instance==null){
synchronized(Singleton2.class){
instance=new Singleton2();
}
}
return instance;
}
}
以上代码线程不安全的原因:当几个线程同时访问的时候,就有可能创建多个对象实例。
2、线程安全的懒汉模式
/**
* 线程安全的懒汉模式
* @Author:小庄
*/
class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
}
return instance;
}
}
以上代码缺点:当getInstance()方法里面的逻辑代码很复杂时,所有的代码都被加锁,会大大的消耗性能
双重检查懒汉模式(线程安全)
/**
* 线程安全的懒汉模式
* @Author:小庄
*/
class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
//进行加锁
synchronized(Singleton.class){
//再进行一次判断类是否为空
if(instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
静态内部类实现单例
/**
*内部类实现单例
* @Author:小庄
*/
class Singleton{
//设置为private
private Singleton(){}
//内部类的特性,外部类不能直接访问
private static class GetSingleton{
private static final Singleton instance=new Singleton();
}
public Singleton getInstance(){
return GetSingleton.instance;
}
}
运用枚举实现单例(推荐使用)
enum Singleton2{
ONE,TWO,THREE;//一个属性代表一个实例,这里有三个实例
}
小结
推荐使用饿汉模式和枚举模式实现单例的原因是线程安全,而且简单明了
不推荐使用懒汉模式的原因是:1、部分的懒汉模式不安全 ;2、过于繁琐 ;3、有可能会对性能造成额外消耗
特点:对类的创建用一个工厂类进行管理。
工厂模式分为:简单工厂,工厂方法和抽象工厂,这节内容主要讲简单工厂和工厂方法。
简单工厂
由一个工厂对象决定创建出哪一种产品类的实例
代替构造函数创建对象,方法名比构造函数清晰。
简单工厂的类图:
public class SimpleFactory{
public createProduct(int i){
switch (i){
case 0: new Product1();break;
case 1: new Product2();break;
case 2: new Product3();break;
default: System.out.println("没有该产品");
}
}
//具体的使用者
public static void main(String[] args){
SimpleFactory factory=new SimpleFactory();
//通过工厂进行创建类
factory.createProduct(1);
}
}
class Product1{}
class Product2{}
class Product3{}
工厂方法
//抽象类
abstract class FactoryMethod {
//生产方法
public abstract void production(String productName);
}
class Product1 extends FactoryMethod {
//实现抽象方法
@Override
public void production(String productName) {
System.out.println("Product1生产了"+productName+"产品");
}
}
class Product2 extends FactoryMethod {
//实现抽象方法
@Override
public void production(String productName) {
System.out.println("Product2生产了"+productName+"产品");
}
}
//使用者
public class Client{
public static void main(String[] args) {
FactoryMethod factory=new Product1();
factory.production("x");
}
}
创建一组有关联的对象实例
角色:
具体实现如下,为了保证代码的阅读,这里不对类的具体操作进行展开
//定义抽象工厂类
abstract class AbstractFactory {
//定义抽象方法,返回值是抽象产品类对象
abstract AbstractClass1 createClass1();
abstract AbstractClass2 createClass2();
abstract AbstractClass3 createClass3();
}
//把抽象产品类全部定义完
abstract class AbstractClass1 {}
abstract class AbstractClass2 {}
abstract class AbstractClass3 {}
//定义具体产品类,分别继承对应的抽象产品类
class Class1 extends AbstractClass1{}
class Class2 extends AbstractClass2{}
class Class3 extends AbstractClass3{}
//定义具体工厂类,实现抽象方法,具体工厂类1
class Factory1 extends AbstractFactory{
@Override
AbstractClass1 createClass1() {
// TODO Auto-generated method stub
return new Class1();
}
@Override
AbstractClass2 createClass2() {
// TODO Auto-generated method stub
return new Class2();
}
@Override
AbstractClass3 createClass3() {
// TODO Auto-generated method stub
return new Class3();
}
}
//具体工厂类2
class Factory2 extends AbstractFactory{
@Override
AbstractClass1 createClass1() {
// TODO Auto-generated method stub
return new Class1();
}
@Override
AbstractClass2 createClass2() {
// TODO Auto-generated method stub
return new Class2();
}
@Override
AbstractClass3 createClass3() {
// TODO Auto-generated method stub
return new Class3();
}
}
分析
从上面代码中,我们可以发现,抽象工厂处理的是产品一族,它们和工厂方法的区别在于:工厂方法有利于处理一个产品的部件扩展维度,而抽象工厂有利于扩展产品一族维度。
特点:必须实现Cloneable接口,并且重写clone方法,否则会报错
应用场景:一个对象属性特别多,同时指定很麻烦,实际工作中用的很少
角色:
浅克隆
//原型接口继承Cloneable接口,或者抽象类实现Cloneable接口
interface Prototype extends Cloneable{
}
//具体原型类实现原型接口,重写方法
public class ConcretePrototype implements Prototype {
@Override
protected Object clone() throws CloneNotSupportedException {
//通过克隆自身对象
ConcretePrototype p=(ConcretePrototype)this.clone();
//返回克隆后的值
return p;
}
}
通过clone实现深拷贝
//原型接口继承Cloneable接口,或者抽象类实现Cloneable接口
interface Prototype extends Cloneable{
}
//具体原型类实现原型接口,重写方法
public class ConcretePrototype implements Prototype {
//假设有一个对象属性,需要克隆这个对象属性
public Book book;
@Override
protected Object clone() throws CloneNotSupportedException {
//对基本属性进行克隆
Object deep=null;
deep=super.clone();
//对引用类型的数据进行单独处理
ConcretePrototype c=(ConcretePrototype )deep;
c.book= (Book)book.clone();
//返回克隆后的值
return deep;
}
}
缺点:繁琐
通过序列化实现深拷贝
public class Book implements Serializable{
//浅克隆,使用默认的clone方法
public Object deepClone() {
ByteArrayInputStream bis=null;
ByteArrayOutputStream bos=null;
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
try{
bos=new ByteArrayOutputStream();
oos=new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
bis=new ByteArrayInputStream(bos.toByteArray());
ois=new ObjectInputStream(bis);
Book book=(Book)ois.readObject();
return book;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
特点:处理复杂对象的创建,在使用时只需要用想要的属性时,不需要设置所有参数;这个建造者模式和模板方法特别像
角色:
//建造者接口或抽象类
interface Builder {
//具体步骤
Builder creteBuilder();
Builder creteBuilder2();
Builder creteBuilder3();
}
//具体建造类
class ConcreteBuilder implements Builder{
//实现具体步骤,返回值为当前对象,便于链式编程
@Override
public Builder creteBuilder() {
System.out.println("建造第一层");
return this;
}
@Override
public Builder creteBuilder2() {
System.out.println("建造第二层");
return this;
}
@Override
public Builder creteBuilder3() {
System.out.println("建造第三层");
return this;
}
}
//监工
class Director {
//将抽象类(接口)聚合,然后对抽象方法进行调用,会指向子类实现的方法
Builder builder;
public Director(Builder builder) {
this.builder=builder;
}
public void toBuilder() {
builder.creteBuilder().creteBuilder2().creteBuilder3();
}
}
//使用者
public class Client {
public static void main(String[] args) {
//通过监工直接建造
Director d=new Director(new ConcreteBuilder());
d.toBuilder();
}
}
比较常用的使用方式
//模拟建造者模式的具体使用
public class Person {
//这里定义了很多的属性,但是有时候只需要部分的属性
int id;
String name;
int age;
double weight;
int score;
//将构造函数设置为私有属性,不让外部进行访问
private Person() {}
//定义内部类,通过内部类对类的成员变量进行操作,可以叫它为静态工厂
public static class PersonBuilder{
Person p=new Person();
//每次方法返回值不为void,而是直接返回当前的对象,有利于链式方程
public PersonBuilder basicInfo(int id,String name,int age) {
p.id=id;
p.name=name;
p.age=age;
return this;
}
public PersonBuilder weight(double weight) {
p.weight=weight;
return this;
}
public PersonBuilder score(int score) {
p.score=score;
return this;
}
//通过下面方法返回外部类对象
public Person build() {return p;}
}
//打印
public static void main(String[] args) {
//采用链式编程,直观
Person p=new Person.PersonBuilder().basicInfo(1, "张三", 18).weight(65.0).build();
}
}
使不兼容的接口相融
角色:
//目标接口
interface Target {
public int open110V();
}
//被适配类
class ClassAdaptee{
public int open220V(){
return 200;
}
}
//适配类
public class ClassAdapte extends ClassAdapteeimplements Target{
@Override
public int open110V() {
int voltage=open220V();
return voltage/2;
}
}
2、对象适配器
和类适配器的区别,适配器和被适配者之间没有继承关系,通过聚合实现(合成复用)
//目标类,可以用抽象类代替
abstract Target {
public abstract int open110V();
}
//被适配类
class ClassAdaptee{
public int open220V(){
return 200;
}
}
//适配类
public class ClassAdapte extends Target{
public ClassAdaptee adaptee;
public ClassAdapte(ClassAdaptee e){
this.adaptee=e;
}
@Override
public int open110V() {
int voltage=e.open220V();
return voltage/2;
}
}
特点:
双维度扩展
分离抽象和具体
用聚合的方式连接抽象和具体
abstract class AbstractBridge {
//聚合实现者
Implementor imt;
}
//具体桥连者
class ConcreteBride extends AbstractBridge{
//把实现者作为参数
public ConcreteBride(Implementor imt) {
this.imt=imt;
}
}
//抽象化实现者
interface Implementor {
}
//具体实现者
public class ConcreteImplementor implements Implementor{
}
特点:对类进行扩展时不修改原有的代码,为类添加新的功能,防止类继承带来的爆炸性增长
//定义Drink抽象类,并设定好抽象方法
abstract class Drink {
private String des;//描述
private float price=0.0f;//价格
public String getDes() {
return des+"价格:"+price;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
//计算费用的抽象方法
protected abstract float cost();
}
//Coffee类继承Drink抽象类,因为Coffee只是一种饮料
abstract class Coffee extends Drink{
}
//定义具体咖啡,并设置好属性
class Cafe_Latte extends Coffee{
public Cafe_Latte() {
super.setDes("拿铁咖啡");
super.setPrice(18.80f);
}
@Override
protected float cost() {
//获取价格
return super.getPrice();
}
}
//咖啡的具体实现类
class Instant_Coffee extends Coffee{
public Instant_Coffee(int shuliang) {
super.setDes("速溶咖啡");
super.setPrice(14.00f);
}
@Override
protected float cost() {
return super.getPrice();
}
}
class Cafe_Latte extends Coffee{
public Cafe_Latte() {
super.setDes("拿铁咖啡");
super.setPrice(18.80f);
}
@Override
protected float cost() {
return super.getPrice();
}
}
//通过继承Drink方便进行装饰类
class DeCorator extends Drink{
private Drink drink;
private String des;//描述
private float price=0.0f;//价格
private int shuliang=1;//数量
public DeCorator(Drink drink) {
this.drink=drink;
}
public DeCorator(Drink drink,int shuliang) {
this.drink=drink;
this.shuliang=shuliang;
}
public String getDes() {
return drink.getDes()+" "+" 加入"+shuliang+"份"+des+" "+des+"单价:"+price;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
protected float cost() {
float material_price=this.price*this.shuliang;
return material_price+drink.cost();
}
}
//装饰者的具体实现类
class Milk extends DeCorator{
public Milk(Drink drink) {
super(drink);
super.setDes("牛奶");
super.setPrice(2f);
}
public Milk(Drink drink, int shuliang) {
super(drink, shuliang);
super.setDes("牛奶");
super.setPrice(2f);
}
}
//装饰者的具体实现类
class Sugar extends DeCorator{
public Sugar(Drink drink) {
super(drink);
super.setDes("糖");
super.setPrice(1f);
}
public Sugar(Drink drink, int shuliang) {
super(drink, shuliang);
super.setDes("糖");
super.setPrice(1f);
}
}
//使用者测试类
public class Client {
public static void main(String[] args) {
Drink order=new Cafe_Latte();
System.out.println("费用:"+order.cost());
System.out.println(order.getDes());
order=new Milk(order);
System.out.println("加入一份牛奶的费用:"+order.cost());
System.out.println(order.getDes());
}
}
特点:共享数据,重复利用对象
应用场景:数据库连接池
下面是图书馆案例,图书馆作为享元池,书架作为抽象化享元对象,书籍作为享元对象。
//抽象化享元对象
abstract class Book {
HashMap<String,Boolean> start=new HashMap<>();
abstract void borrow(Lender lender);
abstract void setBookStart(String bookName,boolean bookStart);
abstract boolean getBookStart(String bookName);
}
//具体享元对象
class MixBook extends Book{
private String bookName="";//书名
private boolean bookStart;
public MixBook(String bookName) {
this.bookName=bookName;
}
@Override
public void borrow(Lender lender) {
System.out.println(lender.getName()+"向图书馆借出一本"+bookName);
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public boolean getBookStart(String bookName) {
if(start.get(bookName)) return true;
else return false;
}
public void setBookStart(String bookName,boolean bookStart) {
start.put(bookName, bookStart);
}
}
//外部状态
class Lender {
private String name;
public Lender(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
import java.util.HashMap;
//享元池
class Library {
//设置图书馆为单例,只能生成一个实例对象
private static Library library=new Library();
//防止外部通过new生成实例
private Library(){};
//书架
HashMap<String,Book> pool=new HashMap<>();
public static Library getInstance() {
return library;
}
public Book toBorrow(String bookName,Lender lender) {
Book book=null;
if(pool.isEmpty()) {
System.out.println("图书馆目前没有书,请添加书籍");
}
else if(!pool.containsKey(bookName)) {
//如果没有,提示图书馆没有这本书,请联系图书管理员
System.out.println("图书馆没有"+bookName+",请联系图书管理员");
}else {
book=pool.get(bookName);
if(!book.getBookStart(bookName)){
System.out.println("你好"+lender.getName()+":"+bookName+"已经被借走了");
book=null;
}
else {
book.start.put(bookName, false);
book.borrow(lender);
}
}
return book;
}
public void shelveBook(String bookName,Book book) {
book.setBookStart(bookName,true);
pool.put(bookName, book);
}
public int poolSize() {
return pool.size();
}
}
//使用享元池
public class Student {
public static void main(String[] args) {
//通过单例模式进行创建图书馆享元池
Library library=Library.getInstance();
library.shelveBook("《Java编程思想》", new MixBook("《Java编程思想》"));
library.shelveBook("《Mysql必会知识》", new MixBook("《Mysql必会知识》"));
//设置借阅人
Lender lender=new Lender("小庄");
Book book1=library.toBorrow("《Java编程思想》",lender);
Book book2=library.toBorrow("《Java编程思想》",lender);
Book book3=library.toBorrow("《Mysql必会知识》",lender);
//查看享元池借出的书籍
System.out.println("图书馆借出书籍共:"+library.poolSize()+"个");
}
}
作用:在程序运行期间,在不修改源代码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
底层实现:在运行期间,通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。
代理模式分为:静态代理,动态代理
本篇内容的动态代理只对jdk代理和cglib代理介绍
静态代理
//抽象化被代理类
interface IBoard {
void draw();
}
//具体被代理类
class Board implements IBoard{
@Override
public void draw() {
System.out.println("被代理类画画操作执行");
}
}
//静态代理类
class StaticProxy implements IBoard{
//聚合抽象化被代理类
private IBoard board;
public StaticProxy(IBoard board) {
this.board=board;
}
//通过代理类执行被代理类的方法
@Override
public void draw() {
System.out.println("代理类执行自己操作");
System.out.print("============");
board.draw();//调用被代理类执行的方法
System.out.print("============");
System.out.println("代理类执行结束");
}
}
//使用者
public class Client {
public static void main(String[] args) {
//通过静态代理类进行调用被代理类的方法
new StaticProxy(new Board()).draw();
}
}
动态代理模式之JDK代理
jdk代理主要通过反射的方式进行代理,JDK代理本身就继承了Proxy类,由于Java不支持多继承,所以不支持对类的代理,只支持对接口的代理。
具体案例如下:
//接口1
interface IBoard {
void draw();
}
//接口2
interface IComputer {
void open();
void complete();
}
//接口1的实现类
class Board implements IBoard{
@Override
public void draw() {
System.out.println("被代理类画画操作执行");
}
}
//接口2的实现类
class Computer implements IComputer{
@Override
public void open() {
System.out.println("电脑正在启动....");
}
@Override
public void complete() {
System.out.println("电脑启动完成");
}
}
//代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
class JDKProxy {
//设置被代理对象
private Object target;
//通过构造函数设置被代理对象
public JDKProxy(Object target) {
this.target=target;
}
//被代理对象生成
public Object getProxyInstance() {
//返回一个JDK代理类对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("=================");
System.out.println("代理开始");
Object object=method.invoke(target, args);
System.out.println("被代理的方法名:"+method.getName());
if("open"==method.getName()) {
Method complete=target.getClass().getMethod("complete");
if(null!=complete){
System.out.println("complete方法被代理对象自动调用");
Thread.sleep(1000);
complete.invoke(target, args);
}
}
System.out.println("代理结束");
System.out.println("=================");
System.out.println();
return object;
}
});
}
}
//使用者
public class Client {
public static void main(String[] args) {
//代理画板对象
JDKProxy board=new JDKProxy(new Board());
IBoard iBoard=(IBoard)board.getProxyInstance();
//调用画板的draw()方法
iBoard.draw();
//代理电脑对象
JDKProxy computer=new JDKProxy(new Computer());
IComputer iComputer=(IComputer) computer.getProxyInstance();
//这里只调用了open()方法,但是complete会被代理对象自动调用
iComputer.open();
}
}
动态代理之cglib代理
我们知道,使用Jdk代理的不足之处是不能对类进行代理,而Cglib代理刚好解决了这个问题。
Cglib可以对无接口的类进行代理,需要实现MethodInterceptor接口
具体案例:
//没有实现接口的类1
class Board{
public void draw() {
System.out.println("被代理类画画操作执行");
}
}
//没有实现接口的类2
class Computer{
public void open() {
System.out.println("电脑正在启动....");
}
public void complete() {
System.out.println("电脑启动完成");
}
}
//Cglib代理
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
//实现MethodInterceptor接口,重写intercept方法(实现代理功能)
class CglibProxy implements MethodInterceptor{
//设置被代理类
public Object target;
//通过构造函数进行设置
public CglibProxy(Object target) {
this.target=target;
}
/**
*实现代理的关键:
*1.创建工具类Enhancer
*2.设置它的父类,会在虚拟机生成一个父类
*3.设置回调函数
*4.创建子类对象,作为代理对象
*/
public Object getProxyInstance() {
//创建工具类
Enhancer e=new Enhancer();
//设置父类
e.setSuperclass(target.getClass());
//设置回调函数
e.setCallback(this);
//创建子类对象,作为代理对象
return e.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
System.out.println("===============");
//代理模式底层使用反射
System.out.println("Cglib代理模式开始");
//invoke激活,和jdk代理功能类似
Object object=method.invoke(target, args);
System.out.println("被代理的方法名:"+method.getName());
//在代理类实现自己的功能
if("open"==method.getName()) {
Method complete=target.getClass().getMethod("complete");
if(null!=complete){
System.out.println("complete方法被代理对象自动调用");
Thread.sleep(1000);
complete.invoke(target, args);
}
}
System.out.println("代理结束");
System.out.println("=================");
System.out.println();
return object;
}
}
另一种方式:不需要类去实现MethodInterceptor接口,是在回调函数的实现这个接口
//没有实现接口的类1
class Board{
public void draw() {
System.out.println("被代理类画画操作执行");
}
}
//没有实现接口的类2
class Computer{
public void open() {
System.out.println("电脑正在启动....");
}
public void complete() {
System.out.println("电脑启动完成");
}
}
//Cglib代理
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
//实现MethodInterceptor接口,重写intercept方法(实现代理功能)
class CglibProxy2{
//设置被代理类
public Object target;
//通过构造函数进行设置
public CglibProxy2(Object target) {
this.target=target;
}
/**
*实现代理的关键:
*1.创建工具类Enhancer
*2.设置它的父类,会在虚拟机生成一个父类
*3.设置回调函数
*4.创建子类对象,作为代理对象
*/
public Object getProxyInstance() {
//创建工具类
Enhancer e=new Enhancer();
//设置父类
e.setSuperclass(target.getClass());
//设置回调函数
e.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("===============");
//代理模式底层使用反射
System.out.println("Cglib代理模式开始");
//invoke激活,和jdk代理功能类似
Object object=method.invoke(target, args);
System.out.println("被代理的方法名:"+method.getName());
//在代理类实现自己的功能
if("open"==method.getName()) {
Method complete=target.getClass().getMethod("complete");
if(null!=complete){
System.out.println("complete方法被代理对象自动调用");
Thread.sleep(1000);
complete.invoke(target, args);
}
}
System.out.println("代理结束");
System.out.println("=================");
System.out.println();
return object;
}
});
//创建子类对象,作为代理对象
return e.create();
}
}
实现代码如下:
//结点
abstract class Node {
public abstract void printNode();
}
//导入相关的包
import java.util.ArrayList;
import java.util.List;
//根结点/子结点
class BranchNode extends Node{
//给结点起个名字
String nodeName;
//将它以下结点进行收集
public List<Node> nodes=new ArrayList<>();
public BranchNode(String nodeName) {
this.nodeName=nodeName;
}
public void addNode(Node node) {
nodes.add(node);
}
//打印结点
@Override
public void printNode() {
System.out.println(nodeName);
}
}
//叶子结点
class LeafNode extends Node{
//给结点起个名字
String nodeName;
public LeafNode(String nodeName) {
this.nodeName=nodeName;
}
//打印叶子结点信息
@Override
public void printNode() {
System.out.println(nodeName);
}
}
//使用者
public class Client {
public static void main(String[] args) {
BranchNode root=new BranchNode("根结点");
BranchNode node1=new BranchNode("结点1");
Node c1=new LeafNode("叶子结点1");
Node c2=new LeafNode("叶子结点2");
//添加结点
root.addNode(node1);
//添加叶子结点
node1.addNode(c1);
node1.addNode(c2);
//使用递归遍历
tree(root,0);
}
public static void tree(Node node,int depth) {
for(int i=0;i<depth;i++) {
System.out.print("--");
}
node.printNode();
//判断是否是根结点
if(node instanceof BranchNode) {
//递归遍历结点
for(Node n:((BranchNode) node).nodes){
tree(n,depth+1);
}
}
}
}
//结点
abstract class Composite {
private String des;
private String name;
public Composite(String name,String des) {
this.name=name;
this.des=des;
}
protected void add(Composite composite) {
}
protected void remove(Composite composite) {}
protected abstract void print();
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//学院(系)
import java.util.HashSet;
class College extends Composite{
HashSet<Major> majors=new HashSet<>();
public College(String name,String des) {
super(name,des);
}
@Override
protected void add(Composite composite) {
majors.add((Major)composite);
}
@Override
protected void remove(Composite composite) {
majors.remove((Major)composite);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("学院:"+getName());
System.out.println();
for(Major major:majors) {
System.out.println("专业:"+major.getName()+"\t专业详情:"+major.getDes());
}
System.out.println("=====================");
}
}
//导入相关包
import java.util.Set;
//学校
class University extends Composite{
//学校由多个学院(系)组成
Set<College> colleges=new HashSet<>();
public University(String name,String des) {
super(name,des);
}
@Override
protected void add(Composite composite) {
colleges.add((College)composite);
}
@Override
protected void remove(Composite composite) {
colleges.remove((College)composite);
}
@Override
public String getName() {
return super.getName();
}
@Override
public String getDes() {
return super.getDes();
}
@Override
protected void print() {
System.out.println("========"+getName()+"========");
System.out.println("简介:"+getDes());
System.out.println();
for(College college:colleges) {
System.out.println("学院:"+college.getName()+"\t学院详情:"+college.getDes());
}
System.out.println("=====================");
}
}
//专业,对于叶子结点
public class Major extends Composite{
public Major(String name,String des) {
super(name,des);
}
@Override
protected void print() {
System.out.println(super.getName()+super.getDes());
}
}
//使用者
public class Client {
public static void main(String[] args) {
University university=new University("清华大学", "中国顶尖学府");
College c=new College("计算机学院","培养软件+硬件高级人才");
university.add(c);
university.add(new College("金融学院", "培养金融行业高级人才"));
university.print();
c.add(new Major("计算机科学与技术","老牌的计算机专业"));
c.print();
}
}
外观模式又称为门面模式,通常和责任链模式结合使用
使用场景:解决多个类之间的复杂关系,只需要通过一个类就可以直接和其他类进行交互,具体使用:中间件
//经纪人,门面
class Agent {
private static Agent agent=new Agent();
//通过单例模式获取类对象
protected Star star=Star.getInstance();;
protected Fans fans=Fans.getInstance();
protected Company company=Company.getInstance();
private Agent() {}
//见面机会方法
protected void meeting() {
System.out.println("粉丝"+fans.getName()+"与"+star.getName()+"获得一次见面机会");
}
//签约方法
protected void contract() {
System.out.println("明星"+star.getName()+"与"+company.getName()+"进行了签约");
}
public static Agent getInstance() {
return agent;
}
}
//明星类
class Star {
private static Star star=new Star();
protected volatile String name="";
private Star() {}
public String getName() {
return name;
}
public synchronized void setName(String name) {
this.name = name;
}
protected static Star getInstance() {
return star;
}
}
//粉丝
class Fans {
private static Fans fans=new Fans();
private volatile String name="";
private Fans() {}
public String getName() {
return name;
}
public synchronized void setName(String name) {
this.name = name;
}
public static Fans getInstance() {
return fans;
}
}
//签约公司
class Company {
private volatile String name="";
private static Company company=new Company();
private Company() {}
public String getName() {
return name;
}
public synchronized void setName(String name) {
this.name = name;
}
public static Company getInstance() {
return company;
}
}
//用户测试
public class Client {
public static void main(String[] args) {
//直接跟经纪人打交道
Agent agent=Agent.getInstance();
agent.company.setName("公司x");
agent.fans.setName("张三");
agent.star.setName("吴签");
agent.meeting();
agent.contract();
System.out.println("============");
agent.fans.setName("李四");
agent.meeting();
agent.contract();
}
}
我们可以看到,经纪人就是一个门面,其他人都是通过经纪人来处理事情。粉丝想要见明星,首先要通过经纪人。再由经纪人和明星打交道。
如果一个类有很多个复杂状态的时候,可以把状态抽象出来,具体状态实现这个抽象类,
角色:
//设置抽象化状态类
abstract class State {
public abstract void simle();
public abstract void cry();
}
//开心状态
class HappyState extends State{
@Override
public void simle() {
System.out.println("开心的笑");
}
@Override
public void cry() {
System.out.println("开心的哭了");
}
}
//不开心状态
class SadState extends State{
@Override
public void simle() {
System.out.println("沮丧的笑着");
}
@Override
public void cry() {
System.out.println("笑哭了");
}
}
//状况
public class Context{
//聚合状态
private State state;
//设置状态
public Context(State state) {
this.state=state;
}
//根据状态判断
public void simle() {
state.simle();
}
//根据状态判断
public void cry() {
state.cry();
}
}
我们不难发现,抽象类的状态(抽象方法)是固定的,具体是怎样的状态,由子类实现。如果抽象类的状态(抽象方法)变化的很频繁,会对所有子类产生影响,那么就不建议使用这个模式
是一种链式的结构的模式,通常使用在审批流,过滤器
//设置责任链的抽象类(接口)
abstract class Approve {
private Approve approve;
//设置下一个审批人
public void setApprove(Approve approve) {
this.approve=approve;
}
//审批人的具体审批内容
public abstract void toApprove();
public abstract void chain(Approve approve);
}
//责任链的内容
//审批人1
class Approve1 extends Approve{
//写入审批人的审批内容
@Override
public void toApprove() {
System.out.println("我是审批人1,我审批完之后交给审批人2");
//设置它的下一个审批人
chain(new Approve2());
}
//设置它的下一个审批人
@Override
public void chain(Approve approve) {
approve.toApprove();
}
}
class Approve2 extends Approve {
@Override
public void toApprove() {
System.out.println("我是审批人2,我审批完之后交给审批人3");
chain(new Approve3());
}
@Override
public void chain(Approve approve) {
approve.toApprove();
}
}
class Approve3 extends Approve {
@Override
public void toApprove() {
System.out.println("我是审批人3,审批完成");
}
@Override
public void chain(Approve approve) {
approve.toApprove();
}
}
//请求访问责任链
public class Request {
public static void main(String[] args) {
Approve approve=new Approve1();
approve.toApprove();
}
}
换一种思路,我们把每一个子类存到容器中,然后对容器进行遍历,然后执行方法,也类似这种链式的执行流程。
我们来通过代码来看看
abstract class Approve {
//审批人的具体审批内容
public abstract void toApprove();
}
//审批人1
class Approve1 extends Approve{
//写入审批人的审批内容
@Override
public void toApprove() {
System.out.println("我是审批人1,我审批完之后交给审批人2");
}
}
//审批人2
class Approve2 extends Approve {
@Override
public void toApprove() {
System.out.println("我是审批人2,我审批完之后交给审批人3");
}
}
//审批人3
class Approve3 extends Approve {
@Override
public void toApprove() {
System.out.println("我是审批人3,审批完成");
}
}
//导入集合
import java.util.ArrayList;
//责任链管理类
class ApproveChain {
//聚合了内容
ArrayList<Approve> approves=new ArrayList<>();
public ApproveChain addChain(Approve approve) {
approves.add(approve);
return this;
}
//通过调用这个方法,遍历容器中的类执行方法
public void chain() {
for(Approve a:approves) {
a.toApprove();
}
}
}
//请求着使用
public class Request {
public static void main(String[] args) {
//定义责任链管理类
ApproveChain ac=new ApproveChain();
//需要设置它的下一个
ac.addChain(new Approve1()).addChain(new Approve2()).addChain(new Approve3());
ac.chain();
}
}
上面代码很类似享元模式吧,哈哈。
角色:
public interface Iterator_ {
boolean hashNext();
Object next();
}
ConcreteIterator(具体的迭代器)
public class ArrayListIterator implements Iterator_{
//单例模式创建类
private static ArrayListAggregate alat=new ArrayListAggregate();
@Override
public boolean hashNext() {
if(alat.currentIndex>=alat.size()) return true;
return false;
}
@Override
public Object next() {
Object o=alat.list.get(alat.currentIndex);
alat.currentIndex++;
return o;
}
}
Aggregate(集合接口)
public interface Aggregate {
public abstract Iterator_ iterator();
}
CocreteAggreagete(具体集合)
import java.util.ArrayList;
public class ArrayListAggregate implements Aggregate{
ArrayList<Object> list=new ArrayList<>();
int index=0;
int currentIndex=0;
@Override
public Iterator_ iterator() {
// TODO Auto-generated method stub
return new ArrayListIterator();
}
public int size() {
return index;
}
public void add(Object o) {
list.add(o);
index++;
}
}
我们开发中,使用到观察者模式很多,这个知识点要重点把握
通知对象状态改变,允许一个对象向所有侦听对象广播自己的消息或事件
角色:
//事件,可定义为抽象化类(接口)
class Event {
String loc;
public Event(String loc) {
this.loc=loc;
}
}
//抽象化观察者
abstract class Observer {
public abstract void actionEvent(Event event);
}
//具体观察者1
class Observer1 extends Observer{
@Override
public void actionEvent(Event event) {
//打印
System.out.println(event.loc);
System.out.println("观察者1做出了行为");
//执行相关的方法
}
}
//具体观察者2
class Observer2 extends Observer{
@Override
public void actionEvent(Event event) {
System.out.println("============");
System.out.println("观察者2做出了行为");
//执行相关的操作
}
}
import java.util.ArrayList;
import java.util.List;
//由事件源发出事件,观察者进行处理事件
public class Source {
private List<Observer> observers=new ArrayList<>();
{
//注册观察者
observers.add(new Observer1());
observers.add(new Observer2());
}
//执行这个方法会触发所有观察者
public void wakeUp() {
for(Observer o:observers) {
o.actionEvent(new Event("bed"));
}
}
}
//测试
class Test {
public static void main(String[] args) {
new Source().wakeUp();
}
}
封装的是不同的执行方式,比如对排序选择不同的排序算法(策略)
代码如下
//抽象化策略类(接口)
interface Sorter{
public abstract void sort(Comparable[] data);
}
//具体策略,这里采用选择排序算法
class SelectSorter implements Sorter{
@Override
public void sort(Comparable[] data) {
for(int i=0;i<data.length-1;i++) {
int min=i;
for(int j=i+1;j<data.length;j++) {
if(data[min].compareTo(data[j])>0) {
min=j;
}
}
swap(data,i,min);
}
}
public void swap(Comparable[] data,int i,int min) {
Comparable temp=data[i];
data[i]=data[min];
data[min]=temp;
}
}
//具体策略类,这里采用冒泡排序
class BubbleSorter implements Sorter{
@Override
public void sort(Comparable[] data) {
//进行排序
for(int i=1;i<data.length;i++) {
for(int j=0;j<data.length-i;j++) {
if(data[j].compareTo(data[j+1])>0) {
Comparable temp=data[j+1];
data[j+1]=data[j];
data[j]=temp;
}
}
}
}
}
//聚合策略类,可以选择不同的策略
class SortAndPrint{
Comparable[] data;
Sorter sorter;
public SortAndPrint(Comparable[] data,Sorter sorter) {
this.data=data;
this.sorter=sorter;
}
public void sort() {
System.out.println("====排序前====");
print();
sorter.sort(data);
System.out.println();
System.out.println("====排序后====");
print();
}
public void print() {
for(int i=0;i<data.length;i++) {
System.out.print(data[i]+",");
}
System.out.println(" ");
}
}
//测试
public class Client {
public static void main(String[] args) {
//定义一个需要排序的数据
String[] data= {"Dumpty","Bowman","Carroll"};
SortAndPrint sap=new SortAndPrint(data, new BubbleSorter());
sap.sort();
}
}
具体实现交给子类
角色:
具体使用:
public abstract class AbstractDisplay {
//定义抽象方法,由子类去实现
public abstract void open();
public abstract void print();
public abstract void close();
//对这个方法设定为final类型。表示子类不能重写
public final void display() {
open();
print();
close();
}
//使用
public static void main(String[] args){
CharDisplay chars=new CharDisplay();
chars.display();
}
}
//子类继承
class CharDisplay extends AbstractDisplay{
@Override
public void open() {
System.out.println("打开CharDisplay");
}
@Override
public void print() {
System.out.println("在CharDisplay进行打印");
}
@Override
public void close() {
System.out.println("关闭CharDisplay");
}
}
//子类继承
class StringDisplay extends AbstractDisplay{
@Override
public void open() {
System.out.println("打开StringDisplay");
}
@Override
public void print() {
System.out.println("在StringDisplay进行打印");
}
@Override
public void close() {
System.out.println("关闭StringDisplay");
}
public void printLine() {
System.out.println("StringDisplay自定义的方法");
}
}
应用场景:
中介这个角色在生活中的理解是:比如租房者找中介,再由中介跟相关的房东沟通,房东也是通过中介和租房者沟通。中介是中间的桥梁。
在中介者模式中的理解和生活中的理解基本一致
角色:
//抽象化中介者
pabstract class Mediator {
//沟通的方法
public abstract void constact(String msg,Colleague c);
}
//具体中介类
class ConcreteMediator extends Mediator{
//聚合同事类
private ConcreteColleague1 c1;
private ConcreteColleague2 c2;
//设置get和set方法
public ConcreteColleague1 getC1() {
return c1;
}
public void setC1(ConcreteColleague1 c1) {
this.c1 = c1;
}
public ConcreteColleague2 getC2() {
return c2;
}
public void setC2(ConcreteColleague2 c2) {
this.c2 = c2;
}
//具体的沟通方法,核心
@Override
public void constact(String msg, Colleague c) {
//判断是哪个同事,进行处理事件
if(c==c1) {
c2.getMessage(msg);
}else {
c1.getMessage(msg);
}
}
}
//同事类
abstract class Colleague {
//给同事类命名
protected String name;
//设置中介
protected Mediator mediator;
public Colleague(String name,Mediator mediator) {
this.name=name;
this.mediator=mediator;
}
//沟通的方法
public abstract void constact(String msg);
//获取信息
public abstract void getMessage(String msg);
}
//具体的同事类,这个类表示租房
class ConcreteColleague1 extends Colleague{
//在构造函数让该类被创建的时候同时命名
public ConcreteColleague1(String name,Mediator mediator) {
super(name, mediator);
}
@Override
public void constact(String msg) {
mediator.constact(msg, this);
}
@Override
public void getMessage(String msg) {
System.out.println();
System.out.println("租房者姓名:"+name+"。收到的信息:"+msg);
}
}
//具体的同事类,这里表示房东
class ConcreteColleague2 extends Colleague{
//在构造函数让该类被创建的时候同时命名
public ConcreteColleague2(String name,Mediator mediator) {
super(name,mediator);
}
@Override
public void constact(String msg) {
mediator.constact(msg, this);
}
@Override
public void getMessage(String msg) {
System.out.println("房东姓名:"+name+"。收到的信息:"+msg);
}
}
//测试类
public class Client {
public static void main(String[] args) {
//创建中介者
ConcreteMediator cm=new ConcreteMediator();
//创建同事类
ConcreteColleague1 c1=new ConcreteColleague1("张三",cm);
ConcreteColleague2 c2=new ConcreteColleague2("李四",cm);
//房东需要知道具体的租房者和房东
cm.setC1(c1);
cm.setC2(c2);
c1.constact("我想租两房一厅的房子");
c2.constact("我这有,而且非常便宜");
}
}
//备忘录,需要存的内容
class Memento {
private String state;
public Memento(String state) {
this.state=state;
}
public String getState() {
return state;
}
}
//创建者,创建备忘录
class Originator {
private String state;
public void setState(String state) {
this.state=state;
//打印状态
System.out.println("现在的状态为:"+state);
}
public String getState() {
return state;
}
//创建备忘录,并存储数据
public Memento saveMemento() {
return new Memento(state);
}
//获取备忘录的数据,恢复备忘录时的状态
public void getStateFromMemento(Memento memento) {
this.state=memento.getState();
}
}
//管理者,备忘录的管理
import java.util.ArrayList;
class Caretaker {
//聚合备忘录
private ArrayList<Memento> mementos=new ArrayList<>();
//添加备忘录
public void addMemento(Memento memento) {
mementos.add(memento);
}
public Memento getMemento(int index) {
return mementos.get(index);
}
}
//测试类
public class Client {
public static void main(String[] args) {
//定义创建类,管理类
Originator o=new Originator();
Caretaker c=new Caretaker();
//设置当时的状态
o.setState("状态1:攻击力:1000");
c.addMemento(o.saveMemento());
o.setState("状态2:攻击力:800");
c.addMemento(o.saveMemento());
String state=c.getMemento(0).getState();
System.out.println("恢复后的状态为:"+state);
}
}
备忘录模式能够随时恢复到备忘录保存的状态,而命令模式需要多个撤销恢复上一个状态。备忘录模也会用在存盘功能,将会使用到序列化和反序化,对于序列化和反序列化的相关使用可以查看这里:
序列化和反序列化的相关知识
可以尝试实现这个功能,这里就不展开介绍了。
需要回退(撤销,Undo)状态的时候通常会使用到命令模式
多次撤销,需要结合责任链模式
宏命令,需要树状结构的组合模式结合使用
命令的调用者和命令的接收者进行了解耦
角色:
//抽象化命令接口
interface Command {
void execute();
void undo();
}
//具体命令
class Command1 implements Command{
private Receive receive;
String str="https://blog.csdn.net/weixin_44715643?spm=1000.2115.3001.5343";
public Command1(Receive receive) {
this.receive=receive;
}
@Override
public void execute() {
System.out.println("接收者的内容:"+receive.msg);
receive.msg+=str;
System.out.println("接收者的内容发生了改变:"+receive.msg);
}
@Override
public void undo() {
//回退到原来的状态
receive.msg=receive.msg.substring(0, receive.msg.length()-str.length());
System.out.println("恢复回上一步的操作时的接收者的内容:"+receive.msg);
}
}
//接收者,对命令做出相应的动作
class Receive {
String msg=new String("hello everybody ");
}
//调用者,聚合了命令
class Invok {
private Command command;
public Invok(Command command) {
this.command=command;
}
public void executeCommand() {
command.execute();
}
public void undoCommand() {
command.undo();
}
}
//使用命令者
public class Client {
public static void main(String[] args) {
Invok invok=new Invok(new Command1(new Receive()));
//执行操作
invok.executeCommand();
//撤销操作
System.out.println("下面进行撤销操作");
invok.undoCommand();
}
}
多个命令的执行和撤销
//抽象化命令接口
abstract class Command {
abstract int getIndex();
abstract void execute();
abstract Command undo();
}
//命令1
import java.util.ArrayList;
class Command1 extends Command{
private ArrayList<String> alist=new ArrayList<>();
private int index=-1;
private Receive receive;
//增加的内容
String str="xxx ";
public Command1(Receive receive) {
this.receive=receive;
}
@Override
public void execute() {
System.out.println("接收者的内容:"+receive.msg);
receive.msg+=str;
System.out.println("接收者的内容发生了改变:"+receive.msg);
alist.add(receive.msg);
index++;
}
@Override
public Command1 undo() {
if(index>=0) {
if(index==0) {
receive.msg=receive.msg.substring(0,receive.chushizhi.length());
alist.remove(index);
index--;
System.out.println("初始值为:"+receive.msg);
}else {
//回退到上一步的状态
alist.remove(index);
//下标往前面移动一位
String s=alist.get(--index);
receive.msg=receive.msg.substring(0, s.length());
System.out.println("恢复回上一步的操作时的接收者的内容:"+receive.msg);
}
}else {
System.out.println("到底了,不能再撤销了");
}
return this;
}
//记录当前的状态
@Override
public int getIndex() {
// TODO Auto-generated method stub
return index;
}
}
//接收者,对命令做出相应的动作
class Receive {
String msg="hello everybody ";
//记录初始值
String chushizhi=msg;
}
//调用者,可以作为使用者Client
class Invok {
private Command command;
public Invok(Command command) {
this.command=command;
}
public void executeCommand() {
command.execute();
}
public Invok undoCommand() {
command.undo();
return this;
}
}
//使用命令者
public class Client {
public static void main(String[] args) {
Invok invok=new Invok(new Command1(new Receive()));
//执行操作
invok.executeCommand();
invok.executeCommand();
invok.executeCommand();
//撤销操作
System.out.println("下面进行撤销操作");
invok.undoCommand();
invok.undoCommand();
invok.undoCommand();
invok.undoCommand();
}
}
数据结构和数据分离
角色:
//抽象化接口
interface Visitor {
void visitCpu(Cpu cpu);
void visitMemory(Memory memory);
void visitBoard(Board board);
}
//具体访问者
class Woman implements Visitor{
//全程七折半
double totalPrice=0.0;
@Override
public void visitCpu(Cpu cpu) {
//打折活动
totalPrice+=cpu.getPrice()*0.75;
}
@Override
public void visitMemory(Memory memory) {
//打折活动
totalPrice+=memory.getPrice()*0.75;
}
@Override
public void visitBoard(Board board) {
//打折活动
totalPrice+=board.getPrice()*0.75;
}
//获取价钱
public double getPrice() {
return totalPrice;
}
}
//具体访问者
class Man implements Visitor{
//购买需要花费的总价钱,全场八折!
double totalPrice=0.0;
@Override
public void visitCpu(Cpu cpu) {
//打折活动
totalPrice+=cpu.getPrice()*0.8;
}
@Override
public void visitMemory(Memory memory) {
totalPrice+=memory.getPrice()*0.8;
}
@Override
public void visitBoard(Board board) {
totalPrice+=board.getPrice()*0.8;
}
//获取价钱
public double getPrice() {
return totalPrice;
}
}
//结构
interface ComputerPart {
void accept(Visitor visitor);
}
class Board implements ComputerPart{
//接待指定的访问人,调用指定的方法
@Override
public void accept(Visitor visitor) {
visitor.visitBoard(this);
}
//设置Board的单价
public double getPrice() {
return 1000.00;
}
}
class Cpu implements ComputerPart{
//接待指定的访问人,调用指定的方法
@Override
public void accept(Visitor visitor) {
visitor.visitCpu(this);
}
//设置Cpu的单价
public double getPrice() {
return 800.0;
}
}
class Memory implements ComputerPart{
//接待指定的访问人,调用指定的方法
@Override
public void accept(Visitor visitor) {
visitor.visitMemory(this);
}
//设置Memory的单价
public double getPrice() {
return 400.00;
}
}
//结构类,根据不同的访问者设定标配的电脑配件
public class Computer {
Cpu cpu=new Cpu();
Memory memory=new Memory();
Board board=new Board();
//给访问者设置标配
public void accept(Visitor visitor) {
this.cpu.accept(visitor);
this.memory.accept(visitor);
this.board.accept(visitor);
}
}
//测试类
public class Test {
public static void main(String[] args) {
//定义相关类
Computer computer=new Computer();
Man man=new Man();
Woman woman=new Woman();
//通过访问者模式进行使用
//一个男人过来购买电脑
computer.accept(man);
System.out.println("男人过来买需要花费:"+man.getPrice());
//一个女人过来购买电脑
computer.accept(woman);
System.out.println("女人过来买需要花费:"+woman.getPrice());
}
}
对于一些固定文法构建一个解释句子的解释器。在实际开发中,我们很少会去开发一个解释器,因为涉及到的知识点比较复杂。所以我们只需要了解即可,我们通过加减法的例子去了解它
角色:
//抽象化解释器
abstract class Expression {
//解释方法
public abstract int interpret(Context context);
}
//导入相关的包
import java.util.HashMap;
//上下文
class Context {
//定义一个键值对的容器
private HashMap<Variable,Integer> map=new HashMap<>();
//把变量名和值存放到容器中
public void addVariable(Variable v,Integer x) {
map.put(v, x);
}
//通过变量名获取值
public int getVlaue(Variable v) {
return map.get(v);
}
}
//变量类,继承解释器
class Variable extends Expression{
//给每个变量定义一个名字
String name;
//通过构造方法给变量名赋值
public Variable(String name) {
this.name=name;
}
//变量解释方法,通过变量获取值
@Override
public int interpret(Context context) {
//通过变量名获取上下文的容器中对应的值
return context.getVlaue(this);
}
//重写toString()方法
@Override
public String toString() {
return name;
}
}
//具体解释器,加法器
class Addition extends Expression{
//定义两个解释器的类,表示传进来的变量
private Expression left;
private Expression right;
//存放进去的是变量
public Addition(Expression left,Expression right) {
this.left=left;
this.right=right;
}
//进行加法运算
@Override
public int interpret(Context context) {
//通过变量的解释器,获取对于的值,进行运算
return left.interpret(context)+right.interpret(context);
}
@Override
public String toString() {
//重写toString方法
return "("+left.toString()+"+"+right.toString()+")";
}
}
//具体解释器,模拟减法器
class Minus extends Expression{
//定义两个解释器变量
private Expression left;
private Expression right;
//通过构造函数的方式传入两个变量
public Minus(Expression left,Expression right) {
this.left=left;
this.right=right;
}
//解释方法
@Override
public int interpret(Context context) {
//通过变量的解释器,获取对于的值,进行运算
return left.interpret(context)-right.interpret(context);
}
@Override
public String toString() {
//重写toString()方法
return "("+left.toString()+"-"+right.toString()+")";
}
}
//测试类
public class Client {
public static void main(String[] args) {
//创建上下文
Context context=new Context();
//创建变量
Variable a=new Variable("a");
Variable b=new Variable("b");
Variable c=new Variable("c");
Variable d=new Variable("d");
//将变量赋予值,并保存到上下文
context.addVariable(a, 1);
context.addVariable(b, 2);
context.addVariable(c, 3);
context.addVariable(d, 4);
//设置表达式
Expression expression=new Addition(a,new Minus(b,new Addition(c,d)));
//对表达式进行解释
int result=expression.interpret(context);
//打印输出结果
System.out.println(expression.toString()+"="+result);
}
}
结语
通过上面的学习,我们发现很多设计模式都十分相似,其实这很正常,因为这些设计模式都是基于Java的继承、多态、聚合、组合等方式完成的。我们应该学习这些模式的设计思想,它们适合在什么场景,并且我们不需要归根到底是哪个设计模式,只要我们类的设计的合理,达到我们的需求即可。通过学习这个知识点,我们能够更加深入的理解开发框架的底层设计原理,有助于我们后面的学习。
我是小庄,欢迎大家和我一起成长。