java设计模式

  • 一、前言
  • 二、七大原则
    • 1、单一原则
    • 2、开闭原则
    • 3、里氏替换原则
    • 4、接口隔离原则
    • 5、依赖倒置原则
    • 6、迪米特法则
    • 7、合成复用原则
  • 三、23种设计模式
    • 1、单例模式(Singleton)
    • 2、工厂模式(Factoy)
    • 3、抽象工厂模式(AbstractFactory)
    • 4、原型模式(Prototype)
    • 5、建造者模式(Builder)
    • 6、适配器模式(Adapte)
    • 7、桥连模式(Bridge)了解
    • 8、装饰者模式(Decorator)
    • 9、享元模式(Flyweight)
    • 10、代理模式(Proxy)
    • 11、组合模式(Composite)
    • 12、外观模式(Facade)
    • 13、状态模式(State)
    • 14、责任链模式(Responsibility)
    • 15、迭代器模式(Iterator)
    • 16、观察者模式(Observer)重要
    • 17、策略模式(Strategy)
    • 18、模板方法模式(Temlapte Method)
    • 19、中介者模式(Mediator)
    • 20、备忘录模式(Memento)
    • 21、命令模式(Command)
    • 22、访问者模式(Visitor)
    • 23、解释器模式(Interpreter)

一、前言

Java设计模式在平时的开发中起到了至关重要的作用。设计模式的主要目的是:
1、降低耦合度,使得类的修改不至于“牵一发而动全身”。
2、提高可扩展性,新增功能对原有的代码没什么影响
3、提高可复用性,降低过多的使用类时,导致类爆炸的情况
4、提高灵活性,代码能够通过接口灵活调用
5、提高可维护性,修改的地方越少

二、七大原则

1、单一原则:一个类只负责一个职责
2、开闭原则:对修改关闭,对扩展开放
3、里氏替换原则:不要破坏继承关系
4、接口隔离原则:暴露最小接口,避免接口过于臃肿
5、依赖倒置原则:面向抽象编程
6、迪米特 法则:尽量不跟陌生人讲话
7、合成复用原则:多使用组合、聚合、少用继承

1、单一原则

一个方法 一个类只负责一个职责,各个职责的程序改动,不影响其它程序,实现 高内聚,低耦合

优点:降低耦合,提高可维护性,对一个类进行单独处理并且不影响其他类

2、开闭原则

对修改关闭,对扩展开放,核心是:抽象化,多态使用
优点:提高可扩展性,提高可维护性,提高可复用性

3、里氏替换原则

所有使用父类的地方,必须能够透明的使用子类对象

例如:父类Animal;子类Dog继承父类Animal,子类Cat继承父类Animal。

Animal animal=new Dog();
//同样可以透明的使用
Animal animal=new Cat();

当子类重写父类的方法时,则不适合使用里氏替换原则。

4、接口隔离原则

每一个接口承担独立的角色,只干自己该干的事情。
只暴露最小接口,实现类不需要用到实现的方法不要放在接口。

5、依赖倒置原则

指的是面向抽象编程,对抽象类或接口进行依赖,比较灵活。
比如:有抽象类Animal,子类Dog继承父类Animal,子类Cat继承父类Animal。在依赖的时候用抽象类,在使用的时候指定子类

//抽象类和子类
abstract class  Animal{abstract void hello();
}
class Dog extends Animal{@Overridevoid hello() {System.out.println("hello ,I am dog");}
}
class Cat extends Animal{@Overridevoid 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();//打印指定的方法}
}

6、迪米特法则

尽量不要跟陌生人说话。
不是陌生人的情况:

  • 当前对象本身(this)
  • 方法参数
  • 对象的成员对象
  • 对象所创建的对象

目的:降低耦合,高内聚

7、合成复用原则

尽量使用组合、聚合的方式,少使用继承。
原因:继承会导致耦合度变高。
聚合方式的使用案例:

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对象的空间。

三、23种设计模式


创建型模式:主要关注点是“怎样创建对象”

1、单例模式(Singleton)

特点:当需求是一个类只需要一个实例
单例模式有: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{//设置为privateprivate 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、有可能会对性能造成额外消耗

2、工厂模式(Factoy)

特点:对类的创建用一个工厂类进行管理。

工厂模式分为:简单工厂,工厂方法和抽象工厂,这节内容主要讲简单工厂和工厂方法。

简单工厂

由一个工厂对象决定创建出哪一种产品类的实例
代替构造函数创建对象,方法名比构造函数清晰。
简单工厂的类图:


具体代码实现:

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 {//实现抽象方法@Overridepublic void production(String productName) {System.out.println("Product1生产了"+productName+"产品");}
}
class Product2 extends FactoryMethod {//实现抽象方法@Overridepublic 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");}
}

3、抽象工厂模式(AbstractFactory)

创建一组有关联的对象实例

角色:

  • AbstractProduct (抽象产品)
  • AbstractFactory (抽象工厂)
  • Client (委托者)


具体实现如下,为了保证代码的阅读,这里不对类的具体操作进行展开

//定义抽象工厂类
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{@OverrideAbstractClass1 createClass1() {// TODO Auto-generated method stubreturn new Class1();}@OverrideAbstractClass2 createClass2() {// TODO Auto-generated method stubreturn new Class2();}@OverrideAbstractClass3 createClass3() {// TODO Auto-generated method stubreturn new Class3();}
}
//具体工厂类2
class Factory2 extends AbstractFactory{@OverrideAbstractClass1 createClass1() {// TODO Auto-generated method stubreturn new Class1();}@OverrideAbstractClass2 createClass2() {// TODO Auto-generated method stubreturn new Class2();}@OverrideAbstractClass3 createClass3() {// TODO Auto-generated method stubreturn new Class3();}
}

分析

从上面代码中,我们可以发现,抽象工厂处理的是产品一族,它们和工厂方法的区别在于:工厂方法有利于处理一个产品的部件扩展维度,而抽象工厂有利于扩展产品一族维度。

4、原型模式(Prototype)

特点:必须实现Cloneable接口,并且重写clone方法,否则会报错
应用场景:一个对象属性特别多,同时指定很麻烦,实际工作中用的很少

角色:

  • Prototype(原型)
  • ConcretePrototype(具体原型)
  • Client(使用者)

浅克隆

//原型接口继承Cloneable接口,或者抽象类实现Cloneable接口
interface Prototype extends Cloneable{
}
//具体原型类实现原型接口,重写方法
public class ConcretePrototype implements Prototype {@Overrideprotected 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;@Overrideprotected 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();}}}
}

5、建造者模式(Builder)

特点:处理复杂对象的创建,在使用时只需要用想要的属性时,不需要设置所有参数;这个建造者模式和模板方法特别像

角色:

  • Builder(建造者)
  • ConcreteBuilder(具体建造者)
  • Director(监工)
  • Client(使用者)
//建造者接口或抽象类
interface Builder {//具体步骤Builder creteBuilder();Builder creteBuilder2();Builder creteBuilder3();
}
//具体建造类
class ConcreteBuilder implements Builder{//实现具体步骤,返回值为当前对象,便于链式编程@Overridepublic Builder creteBuilder() {System.out.println("建造第一层");return this;}@Overridepublic Builder creteBuilder2() {System.out.println("建造第二层");return this;}@Overridepublic 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();}
}

6、适配器模式(Adapte)

使不兼容的接口相融

角色:

  • Target(对象)
  • Adaptee(被适配)
  • Adapter(适配)

1、类适配器模式

//目标接口
interface Target {public int open110V();
}
//被适配类
class ClassAdaptee{public int open220V(){return 200;}
}
//适配类
public class ClassAdapte extends ClassAdapteeimplements Target{@Overridepublic 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;}@Overridepublic int open110V() {int voltage=e.open220V();return voltage/2;}
}

7、桥连模式(Bridge)了解

特点:
双维度扩展
分离抽象和具体
用聚合的方式连接抽象和具体

类图

abstract class AbstractBridge {//聚合实现者Implementor imt;
}
//具体桥连者
class ConcreteBride extends AbstractBridge{//把实现者作为参数public ConcreteBride(Implementor imt) {this.imt=imt;}
}
//抽象化实现者
interface Implementor {}
//具体实现者
public class ConcreteImplementor implements Implementor{}

8、装饰者模式(Decorator)

特点:对类进行扩展时不修改原有的代码,为类添加新的功能,防止类继承带来的爆炸性增长

类图:

案例应用:

//定义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);}@Overrideprotected float cost() {//获取价格return super.getPrice();}
}
//咖啡的具体实现类
class Instant_Coffee extends Coffee{public Instant_Coffee(int shuliang) {super.setDes("速溶咖啡");super.setPrice(14.00f);}@Overrideprotected float cost() {return super.getPrice();}
}
class Cafe_Latte extends Coffee{public Cafe_Latte() {super.setDes("拿铁咖啡");super.setPrice(18.80f);}@Overrideprotected 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());}
}

9、享元模式(Flyweight)

特点:共享数据,重复利用对象

应用场景:数据库连接池

类图:

角色:

  • 抽象化享元对象
  • 享元对象
  • 享元池

下面是图书馆案例,图书馆作为享元池,书架作为抽象化享元对象,书籍作为享元对象。

来看类图

//抽象化享元对象
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;}@Overridepublic 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()+"个");}
}

10、代理模式(Proxy)

作用:在程序运行期间,在不修改源代码的情况下对方法进行功能增强

优势:减少重复代码,提高开发效率,并且便于维护

底层实现:在运行期间,通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,在去调用目标对象的方法,从而完成功能的增强。

代理模式分为:静态代理,动态代理
本篇内容的动态代理只对jdk代理和cglib代理介绍

静态代理


角色:

  • 代理类
  • 被代理类
  • 抽象化被代理类
  • 使用者
//抽象化被代理类
interface IBoard {void draw();
}
//具体被代理类
class Board implements IBoard{@Overridepublic void draw() {System.out.println("被代理类画画操作执行");}
}
//静态代理类
class StaticProxy implements IBoard{//聚合抽象化被代理类private IBoard board;public StaticProxy(IBoard board) {this.board=board;}//通过代理类执行被代理类的方法@Overridepublic 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{@Overridepublic void draw() {System.out.println("被代理类画画操作执行");}
}
//接口2的实现类
class Computer implements IComputer{@Overridepublic void open() {System.out.println("电脑正在启动....");   }@Overridepublic 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() {@Overridepublic 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();}@Overridepublic 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() {@Overridepublic 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();}
}

11、组合模式(Composite)

一般适用于树状结构的场景,比如文件结构,比如层级结构

实现代码如下:

//结点
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);}//打印结点@Overridepublic void printNode() {System.out.println(nodeName);}
}
//叶子结点
class LeafNode extends Node{//给结点起个名字String nodeName;public LeafNode(String nodeName) {this.nodeName=nodeName;}//打印叶子结点信息@Overridepublic 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);}@Overrideprotected void add(Composite composite) {majors.add((Major)composite);}@Overrideprotected void remove(Composite composite) {majors.remove((Major)composite);}@Overridepublic String getName() {return super.getName();}@Overridepublic String getDes() {return super.getDes();}@Overrideprotected 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);}@Overrideprotected void add(Composite composite) {colleges.add((College)composite);}@Overrideprotected void remove(Composite composite) {colleges.remove((College)composite);}@Overridepublic String getName() {return super.getName();}@Overridepublic String getDes() {return super.getDes();}@Overrideprotected 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);}@Overrideprotected 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();}
}

12、外观模式(Facade)

外观模式又称为门面模式,通常和责任链模式结合使用
使用场景:解决多个类之间的复杂关系,只需要通过一个类就可以直接和其他类进行交互,具体使用:中间件

通过案例进行讲解:

//经纪人,门面
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();}
}

我们可以看到,经纪人就是一个门面,其他人都是通过经纪人来处理事情。粉丝想要见明星,首先要通过经纪人。再由经纪人和明星打交道。

13、状态模式(State)

如果一个类有很多个复杂状态的时候,可以把状态抽象出来,具体状态实现这个抽象类,

角色:

  • State(状态)
  • ConcreteState(具体状态)
  • Context(状况)
//设置抽象化状态类
abstract class State {public abstract void simle();public abstract void cry();
}
//开心状态
class HappyState extends State{@Overridepublic void simle() {System.out.println("开心的笑");}@Overridepublic void cry() {System.out.println("开心的哭了");}
}
//不开心状态
class SadState extends State{@Overridepublic void simle() {System.out.println("沮丧的笑着");}@Overridepublic 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();}
}

我们不难发现,抽象类的状态(抽象方法)是固定的,具体是怎样的状态,由子类实现。如果抽象类的状态(抽象方法)变化的很频繁,会对所有子类产生影响,那么就不建议使用这个模式

14、责任链模式(Responsibility)

是一种链式的结构的模式,通常使用在审批流,过滤器

//设置责任链的抽象类(接口)
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{//写入审批人的审批内容@Overridepublic void toApprove() {System.out.println("我是审批人1,我审批完之后交给审批人2");//设置它的下一个审批人chain(new Approve2());}//设置它的下一个审批人@Overridepublic void chain(Approve approve) {approve.toApprove();}
}
class Approve2 extends Approve {@Overridepublic void toApprove() {System.out.println("我是审批人2,我审批完之后交给审批人3");chain(new Approve3());}@Overridepublic void chain(Approve approve) {approve.toApprove();}
}
class Approve3 extends Approve {@Overridepublic void toApprove() {System.out.println("我是审批人3,审批完成");}@Overridepublic 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{//写入审批人的审批内容@Overridepublic void toApprove() {System.out.println("我是审批人1,我审批完之后交给审批人2");}
}
//审批人2
class Approve2 extends Approve {@Overridepublic void toApprove() {System.out.println("我是审批人2,我审批完之后交给审批人3");}
}
//审批人3
class Approve3 extends Approve {@Overridepublic 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();}
}

上面代码很类似享元模式吧,哈哈。

15、迭代器模式(Iterator)

角色:

  • Iterator(迭代器)
  • ConcreteIterator(具体的迭代器)
  • Aggregate(集合)
  • CocreteAggreagete(具体集合)

类图:

Iterator(迭代器)

public interface Iterator_ {boolean hashNext();Object next();
}

ConcreteIterator(具体的迭代器)

public class ArrayListIterator implements Iterator_{//单例模式创建类private static ArrayListAggregate alat=new ArrayListAggregate();@Overridepublic boolean hashNext() {if(alat.currentIndex>=alat.size()) return true;return false;}@Overridepublic 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;@Overridepublic Iterator_ iterator() {// TODO Auto-generated method stubreturn new ArrayListIterator();}public int size() {return index;}public void add(Object o) {list.add(o);index++;}
}

16、观察者模式(Observer)重要

我们开发中,使用到观察者模式很多,这个知识点要重点把握

通知对象状态改变,允许一个对象向所有侦听对象广播自己的消息或事件

角色:

  • Source:事件源对象
  • Observer:观察者
  • Event:事件

//事件,可定义为抽象化类(接口)
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{@Overridepublic void actionEvent(Event event) {//打印System.out.println(event.loc);System.out.println("观察者1做出了行为");//执行相关的方法}
}
//具体观察者2
class Observer2 extends Observer{@Overridepublic 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();}
}

17、策略模式(Strategy)


角色:

  • 抽象化策略
  • 具体策略
  • 聚合策略类
  • 使用者

封装的是不同的执行方式,比如对排序选择不同的排序算法(策略)
代码如下

//抽象化策略类(接口)
interface Sorter{public abstract void sort(Comparable[] data);
}
//具体策略,这里采用选择排序算法
class SelectSorter implements Sorter{@Overridepublic 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{@Overridepublic 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();}
}

18、模板方法模式(Temlapte Method)

具体实现交给子类
角色:

  • AbstractClass
  • concreteClass

类图:

具体使用:

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{@Overridepublic void open() {System.out.println("打开CharDisplay");  }@Overridepublic void print() {System.out.println("在CharDisplay进行打印");}@Overridepublic void close() {System.out.println("关闭CharDisplay");}
}
//子类继承
class StringDisplay extends AbstractDisplay{@Overridepublic void open() {System.out.println("打开StringDisplay");  }@Overridepublic void print() {System.out.println("在StringDisplay进行打印");}@Overridepublic void close() {System.out.println("关闭StringDisplay");}public void printLine() {System.out.println("StringDisplay自定义的方法");}
}

应用场景:

  1. 算法的整体步骤很固定,但其中个别部分易变,将易变部分交给子类实现。
  2. 多个子类存在公共行为,可以将其提取出并集中到一个公共父类以避免代码重复
  3. 需要控制子类的扩展时,模板方法只在特定点调用钩子函数操作,这样就只允许在这些点进行扩展。

19、中介者模式(Mediator)

中介这个角色在生活中的理解是:比如租房者找中介,再由中介跟相关的房东沟通,房东也是通过中介和租房者沟通。中介是中间的桥梁。
在中介者模式中的理解和生活中的理解基本一致

角色:

  • Mediator 抽象化中介者
  • ConcentrateMediator 具体中介者
  • College 抽象化同事类
  • ConcentrateCollege 具体同事类(租房者、房东)

//抽象化中介者
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;}//具体的沟通方法,核心@Overridepublic 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);}@Overridepublic void constact(String msg) {mediator.constact(msg, this);}@Overridepublic 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);}@Overridepublic void constact(String msg) {mediator.constact(msg, this);}@Overridepublic 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("我这有,而且非常便宜");}
}

20、备忘录模式(Memento)

记录状态,便于回滚,经常和命令模式结合使用

角色:

  • Memento 备忘录,记录状态
  • Originator 创建者:创建备忘录
  • Caretaker 管理者:管理备忘录
//备忘录,需要存的内容
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);}
}

备忘录模式能够随时恢复到备忘录保存的状态,而命令模式需要多个撤销恢复上一个状态。备忘录模也会用在存盘功能,将会使用到序列化和反序化,对于序列化和反序列化的相关使用可以查看这里:

序列化和反序列化的相关知识

可以尝试实现这个功能,这里就不展开介绍了。

21、命令模式(Command)

需要回退(撤销,Undo)状态的时候通常会使用到命令模式
多次撤销,需要结合责任链模式
宏命令,需要树状结构的组合模式结合使用

命令的调用者和命令的接收者进行了解耦

角色:

  • invok 调用者
  • Command 命令
  • Receive 接收者


下面代码是对单个命令的执行和撤销作用

//抽象化命令接口
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;}@Overridepublic void execute() {System.out.println("接收者的内容:"+receive.msg);receive.msg+=str;System.out.println("接收者的内容发生了改变:"+receive.msg);}@Overridepublic 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;}@Overridepublic void execute() { System.out.println("接收者的内容:"+receive.msg);receive.msg+=str;System.out.println("接收者的内容发生了改变:"+receive.msg);alist.add(receive.msg);index++;}@Overridepublic 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;}//记录当前的状态@Overridepublic int getIndex() {// TODO Auto-generated method stubreturn 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();}
}

22、访问者模式(Visitor)

数据结构和数据分离

角色:

  • Visitor 访问者抽象类 - Element 具体元素
  • Struct 结构,由多个元素组成
  • 具体元素

//抽象化接口
interface Visitor {void visitCpu(Cpu cpu);void visitMemory(Memory memory);void visitBoard(Board board);
}
//具体访问者
class Woman implements Visitor{//全程七折半double totalPrice=0.0;@Overridepublic void visitCpu(Cpu cpu) {//打折活动totalPrice+=cpu.getPrice()*0.75;}@Overridepublic void visitMemory(Memory memory) {//打折活动totalPrice+=memory.getPrice()*0.75;}@Overridepublic void visitBoard(Board board) {//打折活动totalPrice+=board.getPrice()*0.75;}//获取价钱public double getPrice() {return totalPrice;}
}
//具体访问者
class Man implements Visitor{//购买需要花费的总价钱,全场八折!double totalPrice=0.0;@Overridepublic void visitCpu(Cpu cpu) {//打折活动totalPrice+=cpu.getPrice()*0.8;}@Overridepublic void visitMemory(Memory memory) {totalPrice+=memory.getPrice()*0.8;}@Overridepublic void visitBoard(Board board) {totalPrice+=board.getPrice()*0.8;}//获取价钱public double getPrice() {return totalPrice;}
}
//结构
interface ComputerPart {void accept(Visitor visitor);
}
class Board implements ComputerPart{//接待指定的访问人,调用指定的方法@Overridepublic void accept(Visitor visitor) {visitor.visitBoard(this);}//设置Board的单价public double getPrice() {return 1000.00;}
}
class Cpu implements ComputerPart{//接待指定的访问人,调用指定的方法@Overridepublic void accept(Visitor visitor) {visitor.visitCpu(this);}//设置Cpu的单价public double getPrice() {return 800.0;}
}
class Memory implements ComputerPart{//接待指定的访问人,调用指定的方法@Overridepublic 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());       }
}

23、解释器模式(Interpreter)

对于一些固定文法构建一个解释句子的解释器。在实际开发中,我们很少会去开发一个解释器,因为涉及到的知识点比较复杂。所以我们只需要了解即可,我们通过加减法的例子去了解它

角色:

  • Expression 抽象化解释器
  • Context 上下文,用于存放变量和值
  • Addition 加法解释器(具体解释器)
  • Minus 减法解释器(具体解释器)
  • Variable 变量解释器 (具体解释器),它主要和上下文打交道(获取变量指定的值)

//抽象化解释器
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;}//变量解释方法,通过变量获取值@Overridepublic int interpret(Context context) {//通过变量名获取上下文的容器中对应的值return context.getVlaue(this);}//重写toString()方法@Overridepublic 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;}//进行加法运算@Overridepublic int interpret(Context context) {//通过变量的解释器,获取对于的值,进行运算return left.interpret(context)+right.interpret(context);}@Overridepublic 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;}//解释方法@Overridepublic int interpret(Context context) {//通过变量的解释器,获取对于的值,进行运算return left.interpret(context)-right.interpret(context);}@Overridepublic 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的继承、多态、聚合、组合等方式完成的。我们应该学习这些模式的设计思想,它们适合在什么场景,并且我们不需要归根到底是哪个设计模式,只要我们类的设计的合理,达到我们的需求即可。通过学习这个知识点,我们能够更加深入的理解开发框架的底层设计原理,有助于我们后面的学习。
我是小庄,欢迎大家和我一起成长。

Java设计模式总结篇:七大原则以及23种设计模式简单介绍相关推荐

  1. Java的7大设计原则和23种设计模式

    目录 一.UML类图 二. 设计原则 1.单一职责原则 2.里氏替换原则 3.依赖倒置原则 4.接口隔离原则 5.迪米特法则-最少知道原则 6.开闭原则 7.组合/聚合复用原则 三.Java中的23 ...

  2. 7.Java_模板设计模式---抽象类的实际应用(咖啡和茶的冲泡法),基于抽象类,核心是封装算法。引入钩子方法。开闭原则。23种设计模式

    基于抽象类的模板设计模式,核心是封装算法. 1.模板方法定义了一个算法的步骤,允许子类为一个或多个步骤提供具体实现. 2.模板(模板方法)模式:(典型:Servlet),AQS 在一个方法中定义算法的 ...

  3. java七大设计原则,23种设计模式

    点击查看七大设计原则,23种设计模式 其中 简单工厂.工厂方法.抽象工厂 三种工厂模式中的工厂类的作用基本都是:根据传入的参数创建对应的对象,如果创建的种类太多,那么 简单工厂要写很多 if - el ...

  4. JAVA六大设计原则 和 23种设计模式

    相关书籍:<大话设计模式>.<Java设计模式>.<设计模式之禅>.<研磨设计模式>.<Head First 设计模式> JAVA六大设计原 ...

  5. 面向对象设计原则与23种设计模式

    面向对象概述 1.万物皆对象(Java反射原理-都是借助java.lang.class这个对象的属性.定义等实现) 2.面向对象的特征:封装(对象之间的隔离性.对象内部的属性封装).继承(类的重用,耦 ...

  6. 学习6大设计原则、23种设计模式

    了解设计模式的朋友们,想必都听说过"六大设计原则"吧.其实最经典的 23 种设计模式中或多或少地都在使用这些设计原则,也就是说,设计模式是站在设计原则的基础之上的.所以在学习设计模 ...

  7. Python七大原则,24种设计模式

    七大设计原则: 1.单一职责原则[SINGLE RESPONSIBILITY PRINCIPLE]:一个类负责一项职责.  2.里氏替换原则[LISKOV SUBSTITUTION PRINCIPLE ...

  8. 软件开发设计思想与6大软件设计原则、23种设计模式目录-设计模式

    目录 1.软件开发设计指导思想: (1)可维护性Maintainability (2)可复用性Reusability (3)可扩展性Extensibility/Scalability (4)灵活性fl ...

  9. C++ 设计模式(8大设计原则、23种设计模式)李建忠

    简 述: 设计模式,久闻大名.此记录学习 "C++ 设计模式 李建忠" 的札记,核心共 8大设计原则.23中设计模式.后发现 GitHub 也有类似笔记 Ref1 .Ref2 相关 ...

最新文章

  1. nginx.conf配置文件
  2. Netscreen防火墙常用命令-管理篇
  3. NET问答: LINQ 中为啥不能将 StartsWith() 转成 Like('abc%') ?
  4. 《C++ Primer》13.1.6节练习(部分)
  5. MySQL查询数据字典_存储过程_函数_视图元数据_表元数据_触发器
  6. insertion-sort-list——链表、插入排序、链表插入
  7. 限量!“Java 成长笔记” Spring Boot/Sentinel/Nacos 高并发
  8. hdu1019--Least Common Multiple
  9. Refactoring: Encapsulate Collection
  10. 循环结构程序设计学习心得
  11. Java学习视频教程 云析学院Java高级架构实战系列
  12. 全彩图解电气控制电路100例(PDF)
  13. 数字电路与逻辑设计——组合逻辑应用技巧篇
  14. GIS就业参考系列之方向篇——条条大道通罗马
  15. 机器人资和迅_《机器人与智能系统》-工业机器人与智能机器人杂志-工业自动化领域时尚先锋传媒!...
  16. Delphi调用IE打开网页
  17. 用PS把人物皮肤处理的质感又通透
  18. IAR程序下载起始地址以及加入BOOTLOAD
  19. 基于TextRank算法的单领域多文本摘要(英文摘要)
  20. 牛客网华为机试题(JavaScript)

热门文章

  1. 个人免签即时到账收款接口 bufpay.com 支持多账号收款
  2. hexo-matery主题美化(四)
  3. ux设计中的各种地图_UX中的灰色图案,我们该在有用的设计与有害的设计之间划清界限...
  4. Linux系列讲解 —— Ubuntu18.04安装gcc 9.1.0(C++17)
  5. 1453_TC275 DataSheet阅读笔记14
  6. cocos2dx游戏资源加密之XXTEA
  7. python 使用全局变量_Python教程之全局变量用法
  8. n个重复数字求和问题
  9. python加密解密 sha256_Python hashlib库的使用|md5加密,sha1加密,sha256加密
  10. 编程题:类---矩形类