设计模式
1. oop七大原则
- 开闭原则:对扩展开放,对修改关闭。
- 实现方法:一般使用接口或者抽象类实现开闭原则,具体应用为windows桌面主题设计,用户不用修改系统源代码就可以更换新的主题。
- 里氏替换原则:继承必须确保超类所拥有的性质在子类中仍然成立。
- 实现方法:子类在继承父类时,除添加方法外尽量不要修改父类的方法。
- 依赖倒置原则:要面向接口编程,不要面向实现编程。
- 依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现之间的耦合。
- 实现方法:面向接口编程。
- 单一职责原则:控制类的粒度大小,将对象解耦,提高内聚性。
- 优点:
- 降低复杂度。
- 提高类的可读性。
- 提高系统的可维护性。
- 降低对其他功能的影响。
- 实现方法:发现类的不同职责并将其分离。
- 接口隔离原则:要为各个类建立它们需要的专用接口。
- 实现方法:
- 接口尽量小,一个接口只服务于一个子模块或业务逻辑。
- 接口只提供调用者需要的方法。
- 提高内聚,减少对外交互,使用最少的方法实现最多的功能。
- 迪米特法则: 只与你的直接朋友交谈,不跟“陌生人”说话。
- 实现方法:
- 创建弱耦合的类,类与类之间耦合越弱,更有利于实现复用。
- 尽量降低类成员的访问权限。
- 优先考虑将类设置成不变类。
- 在对其他类的引用上,将引用次数降到最低。
- 谨慎使用序列化功能(类或接口在客户端变更,却未在服务端同步更新,引发序列化失败,,项目管理易疏忽)。
- 不要暴露类成员。
- 合成复用原则:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
- 实现方法:通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。
2. 创建型模式的特点和分类
- 特点:
- 将对象的创建与使用分离,降低系统的耦合度。
- 使用者无需关注对象的创建细节。
单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
单例模式原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。
原型模式工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。
工厂方法抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
抽象工厂模式建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。
建造者模式结构型模式跳转
单例模式
1.定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。
2.使用单例模式可以保证一个类仅有一个实例,并提供一个全局访问点,想要访问该类只能通过使用该对象。
3.具体应用:
懒汉式:懒汉式的核心在于懒加载,好处是使启动速度快,节省资源,一直到实例第一次被访问,才需要初始化实例,坏处是存在线程不安全的问题(可以解决)。
- 懒汉式_01(线程不安全)
/*线程不安全*/
public static Singleton_01 instance=null;
private Singleton_01(){};
public static Singleton_01 getInstance(){
if(instance==null){
instance=new Singleton_01();
}
return instance;
}//最基础的懒汉式写法,可读性高,但多线程场景下线程不安全
- 懒汉式_02(线程安全)
/*线程安全*/
public static volatile Singleton_01 instance=null;
private Singleton_01(){};
public static synchronized Singleton_01 getInstance(){
if(instance==null){
instance=new Singleton_01();
}
return instance;
}/*保证了线程的安全,但开发性能差,因为使用了
synchronized关键字,使其性能退化。*/
- 懒汉式_03(DCL)
/*DCL(double-checked locking)双重校验锁*/
public static volatile Singleton_01 instance=null;
private Singleton_01(){};
public static Singleton_01 getInstance(){
if(instance==null){
synchronized (Singleton_01.class){
if(instance==null){
instance=new Singleton_01();
}
}
}
return instance;
}/*instance添加了关键字volatile,
用来预防指令重排产生“半个对象”的现象,
如果不添加该关键字则会产生以下现象,
因为INSTANCE = new Singleton()
主要分为三步:
1.为对象开辟内存空间
2.对象初始化
3.将对象引用赋值给变量。
如果能够保证2,3的顺序那么就不会存在安全问题
,但是实际因为JIT和处理器会对代码进行优化重排序
,那么可能会2,3的顺序颠倒,
那么就有可能会出现一个线程拿到了一个未被初始完成的对象,
从而引发安全问题
。所以需要添加volatile关键字禁止指令重排序*/
饿汉式:与饱汉相对,饿汉很饿,只想着尽早吃到。所以他就在最早的时机,即类加载时初始化单例,以后访问时直接返回即可。
- 饿汉式
/*饿汉式*/
private static final Singleton_02 instance=new Singleton_02();
private Singleton_02(){};
public static Singleton_02 getInstance(){
return instance;
}/*基于类加载机制,饿汉式天生线程安全,但如果在使用时长期不使用饿汉式
创建实例则会存在内存空间浪费的现象,因为饿汉式在类加载时即实例化。*/
值得注意的时,单线程环境下,饿汉与饱汉在性能上没什么差别;但多线程环境下,由于饱汉需要加锁,饿汉的性能反而更优。
Holder模式:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
- Holder模式
/*Holder模式*/
private static class Holder{
private static final Singleton_03 instance=new Singleton_03();
private Holder(){};
}
private Singleton_03(){};
public static Singleton_03 getInstance(){
return Holder.instance;
}/*相对于饿汉模式,Holder模式仅增加了一个静态内部类的成本,比起懒汉式_03
更加优秀,是一种比较受欢迎的实现方式。建议考虑。*/
枚举:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。不能通过 reflection attack 来调用私有构造方法。
- 枚举
/*枚举*/
public enum Singleton_04 {
INSTANCE;
}/*除了无法使用懒加载机制,其他都是优点。*/
总结:
原型模式
1.定义:原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
2.具体应用:
- 原型模式的应用在于创建出原型,并通过拷贝该原型创建对象。
- 使用:在java中通过修改Cloneable接口的clone方法来实现。
- 使用场景:
- 资源优化场景
- 类初始化需要消耗非常多的资源,通过原型模式可以使用复制来代替创建新对象。
- new一个对象需要非常繁琐的数据或者访问权限
- 在实际使用中,原型模式大多不单独使用,一般是和工厂方法模式一起出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者。
3.实现:
原型模式的克隆分为浅克隆和深克隆。
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
public class Prototype_01 implements Cloneable{
private int id;
private Date date;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}//默认克隆
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Prototype_01(int id, Date date) {
this.id = id;
this.date = date;
}
public Prototype_01() {
}
@Override
public String toString() {
return "Prototype_01{" +
"id=" + id +
", date=" + date +
'}';
}
}/*未使用LomBok是因为使用后hashcode值相同,原因未知,
无法判断是否为一个对象,使用Date因为使用LocalDateTime也
出现hashcode相同的情况原因未知。*/
Date date = new Date();
Prototype_01 p1=new Prototype_01(1,date);
System.out.println(p1);
System.out.println(p1.hashCode());
Prototype_01 p2=(Prototype_01) p1.clone();
System.out.println(p2);
System.out.println(p2.hashCode());
date.setTime(11212);
System.out.println(p1);
System.out.println(p2);
Prototype_01{id=1, date=Tue Oct 20 22:27:38 CST 2020}
2133927002
Prototype_01{id=1, date=Tue Oct 20 22:27:38 CST 2020}
1836019240
Prototype_01{id=1, date=Thu Jan 01 08:00:11 CST 1970}
Prototype_01{id=1, date=Thu Jan 01 08:00:11 CST 1970}
//可以看出,修改了p1的时间后p2的时间也变化了
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
public class Prototype_02 implements Cloneable{
private int id;
private Date date;
@Override
protected Object clone() throws CloneNotSupportedException {
Prototype_02 prototype_02=(Prototype_02)super.clone();
prototype_02.setDate((Date) prototype_02.getDate().clone());
return prototype_02;
}/*修改了原有的克隆,在超类clone的基础上对clone函数进行了个性化,
也保证了Date的克隆。*/
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Prototype_02(int id, Date date) {
this.id = id;
this.date = date;
}
public Prototype_02() {
}
@Override
public String toString() {
return "Prototype_01{" +
"id=" + id +
", date=" + date +
'}';
}
}
Date date1 = new Date();
Prototype_02 p3=new Prototype_02(1,date);
System.out.println(p3);
System.out.println(p3.hashCode());
Prototype_02 p4=(Prototype_02) p3.clone();
System.out.println(p4);
System.out.println(p4.hashCode());
date.setTime(111112);
System.out.println(p3);
System.out.println(p4);
Prototype_02{id=1, date=Thu Jan 01 08:00:11 CST 1970}
325040804
Prototype_02{id=1, date=Thu Jan 01 08:00:11 CST 1970}
1173230247
Prototype_02{id=1, date=Thu Jan 01 08:01:51 CST 1970}
Prototype_02{id=1, date=Thu Jan 01 08:00:11 CST 1970}
//可以看出在对p3的Date进行修改后并未影响到p4的Date
工厂方法:
1.定义:工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
2.介绍:
简单工厂模式:
- 意图:定义一个创建对象的接口,让其子类自己决定实例化那个工厂类,工厂模式使其创建延迟到子类进行。
- 优点:
- 扩展性高,想要增加一个产品,只要扩展一个工具类即可。
- 屏蔽了具体实现方法,只要调用即可。
- 缺点:
- 工厂类代码过于冗余,职责过重,一旦发生异常会严重影响整个系统。
- 如果要扩展的产品过多,会导致产生的类增多,使系统逻辑复杂,导致优点变成缺点。
- 扩展困难,因为每增加一个产品就要修改原来的逻辑。
工厂方法模式:
- 不同:因为简单工厂模式违背了开闭原则,所以工厂方法模式对简单工厂模式进一步抽象化,可以使系统在不修改原来代码的情况下引进新的产品,优缺点同上。
实现:
简单工厂模式:
public interface Shape {
public void show();
}
public class Circle implements Shape{
@Override
public void show() {
System.out.println("circle");
}
}
public class Rectangle implements Shape{
@Override
public void show() {
System.out.println("rectangle");
}
}
public class SimpleFactory {
public static Shape getShape(String shape){
if(shape.equals("circle")){
return new Circle();
}else if(shape.equals("rectangle")){
return new Rectangle();
}
return null;
}
}
public class Factory_01 {
public static void main(String[] args) {
Shape circle = SimpleFactory.getShape("circle");
Shape rectangle = SimpleFactory.getShape("rectangle");
circle.show();
rectangle.show();
}
}
circle
rectangle
工厂方法模式:
public interface Animal {
public void show();
}
public class Horse implements Animal{
@Override
public void show() {
System.out.println("horse");
}
}
public class Pig implements Animal{
@Override
public void show() {
System.out.println("pig");
}
}
public interface AnimalFarm {
public Animal getAnimal();
}
public class HorseFarm implements AnimalFarm{
@Override
public Animal getAnimal() {
System.out.println("我是谁?");
return new Horse();
}
}
public class PigFarm implements AnimalFarm{
@Override
public Animal getAnimal() {
System.out.println("我是谁?");
return new Pig();
}
}
public class Factory_02 {
public static void main(String[] args) {
PigFarm pigFarm = new PigFarm();
HorseFarm horseFarm = new HorseFarm();
Animal pig = pigFarm.getAnimal();
pig.show();
System.out.println("---------------");
Animal horse = horseFarm.getAnimal();
horse.show();
}
}
我是谁?
pig
---------------
我是谁?
horse
抽象工厂模式
1.定义:抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
2.区别:
- 与简单工厂模式和工厂方法模式相比,抽象工厂方法更加抽象,前两种方法只能生产同等级的商品,类型过于单一,比如以农场举例子,按照前两种方法进行设计只能设计出单一的农场,马场只有马,猪场只有但农场不应该使这样,农场是一个多元化的共和体,既可以养动物也可以种植物等。
- 考虑多产品类型参考下图
- 抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
3.实现:
public interface Animal {
public void show();
}
public class Pig implements Animal {
@Override
public void show() {
System.out.println("pig");
}
}
public class Horse implements Animal {
@Override
public void show() {
System.out.println("horse");
}
}
public interface Fruit {
public void taste();
}
public class Apple implements Fruit{
@Override
public void taste() {
System.out.println("十三香");
}
}
public class Banana implements Fruit{
@Override
public void taste() {
System.out.println("好吃");
}
}
public interface Farm {
public Animal getAnimal();
public Fruit getFruit();
}
public class HorseFarm implements Farm {
@Override
public Animal getAnimal() {
System.out.println("我是谁?");
return new Horse();
}
@Override
public Fruit getFruit() {
System.out.println("咋样");
return new Apple();
}
}
public class PigFarm implements Farm {
@Override
public Animal getAnimal() {
System.out.println("我是谁?");
return new Pig();
}
@Override
public Fruit getFruit() {
System.out.println("咋样");
return new Banana();
}
}
public class Factory_03 {
public static void main(String[] args) {
PigFarm pigFarm = new PigFarm();
HorseFarm horseFarm = new HorseFarm();
Animal animal = pigFarm.getAnimal();
animal.show();
Fruit fruit = pigFarm.getFruit();
fruit.taste();
System.out.println("----------------");
Animal animal1 = horseFarm.getAnimal();
animal1.show();
Fruit fruit1 = horseFarm.getFruit();
fruit1.taste();
}
}
我是谁?
pig
咋样
好吃
----------------
我是谁?
horse
咋样
十三香
建造者模式
1.定义:建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。
2.介绍:
- 解决问题:在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
- 优点:建造者独立,易扩展,便于控制细节风险
- 缺点:产品必须要有共同点,范围有限制;如果内部变化复杂,会有许多的建筑类。
- 适用场景:
- 相同的方法,不同的执行顺序,产生不同的结果。
- 多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。
- 产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。
- 初始化一个对象特别复杂,参数多,而且很多参数都具有默认值。
- 区别:
- 建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。举个例子讲,把产品比作一个汽车,工厂模式就是生产汽车的各种零部件,而建筑者模式则是负责将这些零部件组装起来形成汽车,二者搭配可以相辅相成。
- 建造者模式更加注重方法的调用顺序,工厂模式注重创建对象。
- 创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的对象都一样哦。
3.实现:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private int id;
private int cost;
}
public abstract class Worker {
abstract void upd();
abstract void del();
abstract void sel();
abstract void ins();
}
public class ShopWorker extends Worker {
@Override
void upd() {
System.out.println("更新商品");
}
@Override
void del() {
System.out.println("删除商品");
}
@Override
void sel() {
System.out.println("查询商品");
}
@Override
void ins() {
System.out.println("添加商品");
}
}
public class ShopManager {
private Worker worker;
public ShopManager(Worker worker){
this.worker=worker;
}
public void use(){
worker.ins();
worker.sel();
worker.upd();
worker.del();
}
}
public class Builder_01 {
public static void main(String[] args) {
/*使用管理者方式*/
ShopManager shopManager = new ShopManager(new ShopWorker());
shopManager.use();
System.out.println("-----------");
/*不使用*/
ShopWorker shopWorker = new ShopWorker();
shopWorker.ins();
shopWorker.del();
}
}
3. 结构型模式的特点和分类
- 特点:
- 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。
- 使由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。
- 除了适配器模式分为类结构型模式和对象结构型模式两种,其他的全部属于对象结构型模式。
代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
代理模式适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
适配器模式桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
桥接模式装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。
装饰模式外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
外观模式享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。
享元模式组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。
组合模式行为型模式跳转
代理模式
1.定义:在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
2.介绍:
-
优点:
- 通过在类之间添加中间层解决直接访问对象的问题。
- 职责清晰
- 高扩展性
-
注意事项:
- 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
- 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
3.实现:
静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
public interface Food {
public void eat();
}
public class Baby implements Food{
@Override
public void eat() {
System.out.println("啊");
}
}
public class Baby_sitter implements Food{
Baby baby;
public Baby_sitter(Baby baby){
this.baby=baby;
}
@Override
public void eat() {
System.out.println("我喂你吃");
baby.eat();
}
}
public class Proxy_01 {
public static void main(String[] args) {
Baby baby = new Baby();
Baby_sitter baby_sitter = new Baby_sitter(baby);
baby_sitter.eat();
}
}
我喂你吃
啊
动态代理:在程序运行时,运用反射机制动态创建而成
Java中常见的动态代理有:JDK动态代理、cglib、ASM和bytebuddy等
- 动态代理工作的基本模式就是将自己的方法功能的实现交给 InvocationHandler角色,外界对Proxy角色中的每一个方法的调用,Proxy角色都会交给InvocationHandler来处理,而InvocationHandler则调用具体对象角色的方法。如下图所示:
在面向对象的编程之中,如果我们想要约定Proxy 和RealSubject可以实现相同的功能,有两种方式:
-
a.一个比较直观的方式,就是定义一个功能接口,然后让Proxy 和RealSubject来实现这个接口。
-
b.还有比较隐晦的方式,就是通过继承。因为如果Proxy 继承自RealSubject,这样Proxy则拥有了RealSubject的功能,
Proxy还可以通过重写RealSubject中的方法,来实现多态。
其中JDK中提供的创建动态代理的机制,是以a 这种思路设计的,而cglib 则是以b思路设计的。
- a:jdk动态代理:
Java在JDK1.3后引入的动态代理机制,使我们可以在运行期动态的创建代理类。动态代理是在运行期间通过接口生成代理类的,与静态代理相比更加灵活,但是也有一定的限制,第一是代理对象必须实现一个接口,否则会报异常,因为其原理就是根据接口来生成代理对象的。第二是有性能问题,因为是通过反射来实现调用的,所以比正常的直接调用来得慢,并且通过生成类文件也会多消耗部分方法区空间,可能引起Full GC。-
现在想为RealSubject这个类创建一个动态代理对象,JDK主要会做以下工作:
-
- 获取 RealSubject上的所有接口列表;
-
- 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX ;
-
- 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
-
- 将对应的字节码转换为对应的class 对象;
-
- 创建InvocationHandler 实例handler,用来处理Proxy所有方法调用;
-
- Proxy 的class对象 以创建的handler对象为参数,实例化一个proxy对象
-
-
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
- (1)Interface InvocationHandler:该接口中仅定义了一个方法
- public object invoke(Object obj,Method method, Object[]args)在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。
- (1)Interface InvocationHandler:该接口中仅定义了一个方法
-
(2)Proxy:该类即为动态代理类,其中主要包含以下内容:
-
protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。
-
static Class getProxyClass (ClassLoaderloader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
-
static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)
-
所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
-
在使用动态代理类时,我们必须实现InvocationHandler接口
-
通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
-
-
动态代理步骤:
- 1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
- 2.创建被代理的类以及接口
- 3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理 - 4.通过代理调用方法
-
详细过程参考博客,简单总结就是通过newInstance实现的实例其实本质是继承了Proxy类并实现了我们的接口,当我们调用接口方法时实际调用的是我们重写的invoke方法。
-
public interface Food {
public void eat();
}
public class Baby implements Food {
@Override
public void eat() {
System.out.println("啊");
}
}
public class Proxy_InvocationHandler implements InvocationHandler {
private Object o;
public Proxy_InvocationHandler(Object o){
this.o= o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我喂你吃");
method.invoke(o,null);
return null;
}
}
public class Proxy_02 {
public static void main(String[] args) {
Baby baby=new Baby();
Proxy_InvocationHandler pr= new Proxy_InvocationHandler(baby);
Object o = Proxy.newProxyInstance(baby.getClass().getClassLoader(),baby.getClass().getInterfaces(),pr);
Food f=(Food)o;
f.eat();
}
}
我喂你吃
啊
- b:cglib动态代理:
cglib代理的类,无需强制实现接口,其生成的代理类 是 被代理类的子类,并且重写了被代理类的方法,但是需要额外的引入Jar
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
public class Baby{
public void eat() {
System.out.println("啊");
}
}
public class Proxy_methodInterceptor implements MethodInterceptor {
private Object object;
public Proxy_methodInterceptor(Object object){
this.object=object;
}
@Override
/**
* 实现回调方法
* @param o 代理的对象
* @param method 被代理对象的方法
* @param object 参数集合
* @param methodProxy 生成的代理类的方法
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("你吃了吗");
method.invoke(object,null);
return null;
}
}
public class Proxy_03 {
public static void main(String[] args) {
Baby baby = new Baby();
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(baby.getClass());
Proxy_methodInterceptor proxy_methodInterceptor = new Proxy_methodInterceptor(baby);
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦截
enhancer.setCallback(proxy_methodInterceptor);
// 创建动态代理类对象并返回
Baby o =(Baby)enhancer.create();
// 调用
o.eat();
}
}
ASM
ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为(也就是生成的代码可以覆盖原来的类也可以是原始类的子类)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
不过ASM在创建class字节码的过程中,操纵的级别是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有一定的了解。ASM提供了两组API:Core API 和Tree API,Core API是基于访问者模式来操作类的,而Tree是基于树节点来操作类的
没学会,学会再补
javassist
Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。一句话总结就是:Javassit其实就是一个二方包,提供了运行时操作Java字节码的方法。
Java代码编译完生成.class文件,就JVM(准确说是JIT)会解释执行这些字节码(转换为机器码并执行),由于字节码的解释执行是在运行时进行的,那我们能否手工编写或者更改字节码,再由JVM执行呢?答案是肯定的,而Javassist就提供了一些方便的方法,让我们通过这些方法生成字节码,而不用关注class文件数据格式。
javassist
Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。一句话总结就是:Javassit其实就是一个二方包,提供了运行时操作Java字节码的方法。
Java代码编译完生成.class文件,就JVM(准确说是JIT)会解释执行这些字节码(转换为机器码并执行),由于字节码的解释执行是在运行时进行的,那我们能否手工编写或者更改字节码,再由JVM执行呢?答案是肯定的,而Javassist就提供了一些方便的方法,让我们通过这些方法生成字节码,而不用关注class文件数据格式。
<dependency>
<groupId>de.scrum-master.org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.27.0-GA-bugfix-328</version>
</dependency>
public class Proxy_04 {
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
ClassPool pool = ClassPool.getDefault();
// 1. 创建一个空类
CtClass cc = pool.makeClass("com.q.proxy.dynamic_proxy_javassist.Person");
// 2. 新增一个字段 private String name;
// 字段名为name
CtField param = new CtField(pool.get("java.lang.String"), "name", cc);
// 访问级别是 private
param.setModifiers(Modifier.PRIVATE);
// 初始值是 "xiaoming"
cc.addField(param, CtField.Initializer.constant("xiaoming"));
// 3. 生成 getter、setter 方法
cc.addMethod(CtNewMethod.setter("setName", param));
cc.addMethod(CtNewMethod.getter("getName", param));
// 4. 添加无参的构造函数
CtConstructor cons = new CtConstructor(new CtClass[]{}, cc);
cons.setBody("{name = \"xiaohong\";}");
cc.addConstructor(cons);
// 5. 添加有参的构造函数
cons = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, cc);
// $0=this / $1,$2,$3... 代表方法参数
cons.setBody("{$0.name = $1;}");
cc.addConstructor(cons);
// 6. 创建一个名为printName方法,无参数,无返回值,输出name值
CtMethod ctMethod = new CtMethod(CtClass.voidType, "printName", new CtClass[]{}, cc);
ctMethod.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("{System.out.println(name);}");
cc.addMethod(ctMethod);
//这里会将这个创建的类对象编译为.class文件
cc.writeFile("D:\\tool\\IdeaProjects\\Design_Pattern_Test\\src\\main\\java");
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.q.proxy.dynamic_proxy_javassist;
public class Person {
private String name = "xiaoming";
public void setName(String var1) {
this.name = var1;
}
public String getName() {
return this.name;
}
public Person() {
this.name = "xiaohong";
}
public Person(String var1) {
this.name = var1;
}
public void printName() {
System.out.println(this.name);
}
}
不太会所以copy的
bytebuddy
Byte Buddy是致力于解决字节码操作和 instrumentation API 的复杂性的开源框架。Byte Buddy 所声称的目标是将显式的字节码操作隐藏在一个类型安全的领域特定语言背后。通过使用 Byte Buddy,任何熟悉 Java 编程语言的人都有望非常容易地进行字节码操作。
public interface Singable {
/**
* 唱歌
*/
void sing();
}
public class Singer implements Singable {
@Override
public void sing() {
System.out.println("I am singing...");
}
}
public class Client {
public static void main(String[] args) throws Exception {
Singable proxy = createByteBuddyDynamicProxy();
proxy.sing();
System.out.println(proxy.toString());
}
private static Singable createByteBuddyDynamicProxy() throws Exception {
return (Singable) new ByteBuddy().subclass(Object.class)
.implement(Singable.class)
.method(ElementMatchers.named("sing"))
.intercept(InvocationHandlerAdapter.of(new SingerInvocationHandler(new Singer())))
.make()
.load(Client.class.getClassLoader())
.getLoaded()
.getDeclaredConstructor()
.newInstance();
}
public static class SingerInvocationHandler implements InvocationHandler {
private Object delegate;
public SingerInvocationHandler(Object delegate) {
this.delegate = delegate;
}
/**
* 动态代理调用方法
*
* @param o 生成的代理对象
* @param method 代理的方法
* @param objects 方法参数
*/
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("bytebuddy proxy before sing ");
Object ret = method.invoke(delegate,objects);
System.out.println("bytebuddy proxy after sing ");
return ret;
}
}
}
学废了
适配器模式
1.定义:适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。
2.介绍:
- 意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 应用实例:java的jdbc
- 分类:适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。
3.实现:
类继承:
interface Target
{
public void request();
}
class Adaptee
{
public void specificRequest()
{
System.out.println("适配者中的业务代码被调用!");
}
}
class ClassAdapter extends Adaptee implements Target
{
public void request()
{
specificRequest();
}
}
public class Adapter_01 {
public static void main(String[] args)
{
System.out.println("类适配器模式测试:");
Target target = new ClassAdapter();
target.request();
}
}
对象继承:
interface Target
{
public void request();
}
class Adaptee
{
public void specificRequest()
{
System.out.println("适配者中的业务代码被调用!");
}
}
class ObjectAdapter implements Target
{
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee)
{
this.adaptee=adaptee;
}
public void request()
{
adaptee.specificRequest();
}
}
public class Adapter_02 {
public static void main(String[] args) {
System.out.println("对象适配器模式测试:");
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
桥接模式
1.定义:桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。
2.介绍:
- 意图:将抽象部分与实现部分分离,使它们都可以独立的变化。
- 桥接模式通常适用于以下场景。
- 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。
- 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。
- 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。
3.实现:
public interface DrawAPI {
public void drawCircle(int radius, int x, int y);
}
public class GreenCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: green, radius: "
+ radius +", x: " +x+", "+ y +"]");
}
}
public class RedCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: red, radius: "
+ radius +", x: " +x+", "+ y +"]");
}
}
public abstract class Shape {
protected DrawAPI drawAPI;//类型为protected,子类继承还可以使用
protected Shape(DrawAPI drawAPI){
this.drawAPI = drawAPI;
}
public abstract void draw();
}
public class Circle_Shape extends Shape {
private int x, y, radius;
public Circle_Shape(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawAPI.drawCircle(radius,x,y);
}
}
public class Bridge_01 {
public static void main(String[] args) {
Shape redCircle = new Circle_Shape(100,100, 10, new RedCircle());
Shape greenCircle = new Circle_Shape(100,100, 10, new GreenCircle());
redCircle.draw();
greenCircle.draw();
}
}
装饰模式
1.定义:装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
2.介绍:
- 功能:动态地给一个对象添加一些额外的职责。
- 何时使用:在不想增加很多子类的情况下扩展类。
3.实现:
public interface Shape {
void draw();
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
public class Decorator_01 {
public static void main(String[] args) {
Shape circle = new Circle();
ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
//Shape redCircle = new RedShapeDecorator(new Circle());
//Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();
System.out.println("\nCircle of red border");
redCircle.draw();
System.out.println("\nRectangle of red border");
redRectangle.draw();
}
}
Circle with normal border
Shape: Circle
Circle of red border
Shape: Circle
Border Color: Red
Rectangle of red border
Shape: Rectangle
Border Color: Red
外观模式
1.定义:外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
2.介绍:
- 意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 外观(Facade)模式又叫作门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
3.实现:
class SubSystem01
{
public void method1()
{
System.out.println("子系统01的method1()被调用!");
}
}
class SubSystem02
{
public void method2()
{
System.out.println("子系统02的method2()被调用!");
}
}
class SubSystem03
{
public void method3()
{
System.out.println("子系统03的method3()被调用!");
}
}
class Facade
{
private SubSystem01 obj1=new SubSystem01();
private SubSystem02 obj2=new SubSystem02();
private SubSystem03 obj3=new SubSystem03();
public void method()
{
obj1.method1();
obj2.method2();
obj3.method3();
}
}
public class Facade_01 {
public static void main(String[] args) {
Facade f=new Facade();
f.method();
}
}
享元模式
1.定义:享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。
2.介绍:
- 意图:运用共享技术有效地支持大量细粒度的对象。
- 主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
3.实现:
public interface Shape {
void draw();
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Circle implements Shape {
private String color;
private int x;
private int y;
private int radius;
public Circle(String color){
this.color=color;
}
@Override
public void draw() {
System.out.println("Circle: Draw() [Color : " + color
+", x : " + x +", y :" + y +", radius :" + radius);
}
}
public class ShapeFactory {
private static final HashMap<String, Shape> circleMap = new HashMap<>();
public static Shape getCircle(String color) {
Circle circle = (Circle)circleMap.get(color);
if(circle == null) {
circle = new Circle(color);
circleMap.put(color, circle);
System.out.println("Creating circle of color : " + color);
}
return circle;
}
}
public class FlyWeight_01 {
private static final String colors[] =
{ "Red", "Green", "Blue", "White", "Black" };
public static void main(String[] args) {
for(int i=0; i < 5; ++i) {
Circle circle =
(Circle)ShapeFactory.getCircle(getRandomColor());
circle.setX(getRandomX());
circle.setY(getRandomY());
circle.setRadius(100);
circle.draw();
}
}
private static String getRandomColor() {
return colors[(int)(Math.random()*colors.length)];
}
private static int getRandomX() {
return (int)(Math.random()*100 );
}
private static int getRandomY() {
return (int)(Math.random()*100);
}
}
组合模式
1.定义:组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
2.介绍:
- 意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
- 如何解决:树枝和叶子实现统一接口,树枝内部组合该接口。
- 关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component。
3.实现:
interface Component
{
public void add(Component c);
public void remove(Component c);
public Component getChild(int i);
public void operation();
}
class Leaf implements Component
{
private String name;
public Leaf(String name)
{
this.name=name;
}
public void add(Component c){ }
public void remove(Component c){ }
public Component getChild(int i)
{
return null;
}
public void operation()
{
System.out.println("树叶"+name+":被访问!");
}
}
class Composite implements Component
{
private ArrayList<Component> children=new ArrayList<Component>();
public void add(Component c)
{
children.add(c);
}
public void remove(Component c)
{
children.remove(c);
}
public Component getChild(int i)
{
return children.get(i);
}
public void operation()
{
for(Object obj:children)
{
((Component)obj).operation();
}
}
}
public class Composite_01 {
public static void main(String[] args)
{
Component c0=new Composite();
Component c1=new Composite();
Component leaf1=new Leaf("1");
Component leaf2=new Leaf("2");
Component leaf3=new Leaf("3");
c0.add(leaf1);
c0.add(c1);
c1.add(leaf2);
c1.add(leaf3);
c0.operation();
}
}
2. 行为型模式的特点和分类
- 特点:
- 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
- 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。
模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
模板方法模式策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。
策略模式命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。
命令模式职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。
责任链模式状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。
状态模式观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。
观察者模式中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。
中介者模式迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
迭代器模式访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。
访问者模式 ### 备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。 备忘录模式解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。
解释器模式模板模式
1.定义:在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
2.介绍:
- 意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。例如,去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
3.实现:
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戏
initialize();
//开始游戏
startPlay();
//结束游戏
endPlay();
}
}
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
public class Template_01 {
public static void main(String[] args) {
Cricket cricket = new Cricket();
cricket.play();
System.out.println();
Football football = new Football();
football.play();
}
}
策略模式
1.定义:在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
2.介绍:
- 意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
- 在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等,超市促销可以釆用打折、送商品、送积分等方法。在软件开发中也常常遇到类似的情况,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。
3.实现:
public interface Strategy {
public int doOperation(int num1, int num2);
}
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
public class Strategy_01 {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
命令模式
1.定义:命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
2.介绍:
- 主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
- 在现实生活中,这样的例子也很多,例如,电视机遥控器(命令发送者)通过按钮(具体命令)来遥控电视机(命令接收者),还有计算机键盘上的“功能键”等。
3.实现:
//调用者
public class Invoker
{ //命令
private Command command;
public Invoker(Command command)
{
this.command=command;
}
public void setCommand(Command command)
{
this.command=command;
}
public void call()
{
System.out.println("调用者执行命令command...");
command.execute();
}
}
//抽象命令
public interface Command
{
public abstract void execute();
}
//具体命令
public class ConcreteCommand implements Command
{ //接受
private Receiver receiver;
ConcreteCommand()
{
receiver=new Receiver();
}
public void execute()
{
receiver.action();
}
}
//接收者
public class Receiver
{
public void action()
{
System.out.println("接收者的action()方法被调用...");
}
}
public class Command_01 {
public static void main(String[] args) {
Command command=new ConcreteCommand();
Invoker invoker = new Invoker(command);
System.out.println("客户访问调用者的call()方法...");
invoker.call();
}
}
责任链模式
1.定义:顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
2.介绍:
- 在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。
- 在计算机软硬件中也有相关例子,如总线网中数据报传送,每台计算机根据目标地址是否同自己的地址相同来决定是否接收;还有异常处理中,处理程序根据异常的类型决定自己是否处理该异常;还有 Struts2 的拦截器、JSP 和 Servlet 的 Filter 等,所有这些,如果用责任链模式都能很好解决。
3.实现:
//抽象处理者:领导类
public abstract class Leader
{
private Leader next;
public void setNext(Leader next)
{
this.next=next;
}
public Leader getNext()
{
return next;
}
//处理请求的方法
public abstract void handleRequest(int LeaveDays);
}
//具体处理者1:班主任类
public class ClassAdviser extends Leader
{
public void handleRequest(int LeaveDays)
{
if(LeaveDays<=2)
{
System.out.println("班主任批准您请假" + LeaveDays + "天。");
}
else
{
if(getNext() != null)
{
getNext().handleRequest(LeaveDays);
}
else
{
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者2:系主任类
public class DepartmentHead extends Leader
{
public void handleRequest(int LeaveDays)
{
if(LeaveDays<=7)
{
System.out.println("系主任批准您请假" + LeaveDays + "天。");
}
else
{
if(getNext() != null)
{
getNext().handleRequest(LeaveDays);
}
else
{
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者3:院长类
public class Dean extends Leader
{
public void handleRequest(int LeaveDays)
{
if(LeaveDays<=10)
{
System.out.println("院长批准您请假" + LeaveDays + "天。");
}
else
{
if(getNext() != null)
{
getNext().handleRequest(LeaveDays);
}
else
{
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
//具体处理者4:教务处长类
public class DeanOfStudies extends Leader
{
public void handleRequest(int LeaveDays)
{
if(LeaveDays<=20)
{
System.out.println("教务处长批准您请假"+LeaveDays+"天。");
}
else
{
if(getNext()!=null)
{
getNext().handleRequest(LeaveDays);
}
else
{
System.out.println("请假天数太多,没有人批准该假条!");
}
}
}
}
public class Chain_of_Responsibility_01 {
public static void main(String[] args) {
Dean dean = new Dean();
ClassAdviser classAdviser = new ClassAdviser();
DeanOfStudies deanOfStudies = new DeanOfStudies();
DepartmentHead departmentHead = new DepartmentHead();
classAdviser.setNext(departmentHead);
departmentHead.setNext(dean);
dean.setNext(deanOfStudies);
classAdviser.handleRequest(12);
}
}
状态模式
1.定义:在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
2.介绍:
- 对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的情况全都考虑到,然后使用 if-else语句来做状态判断,再进行不同情况的处理。但当对象的状态很多时,程序会变得很复杂。而且增加新的状态要添加新的 if-else 语句,这违背了“开闭原则”,不利于程序的扩展。以上问题如果采用“状态模式”就能很好地得到解决。状态模式的解决思想是:当控制一个对象状态转换的条件表达式过于复杂时,把相关“判断逻辑”提取出来,放到一系列的状态类当中,这样可以把原来复杂的逻辑判断简单化。
3.实现:
public class Context {
private State state;
public Context(){
state = null;
}
public void setState(State state){
this.state = state;
}
public State getState(){
return state;
}
}
public interface State {
public void doAction(Context context);
}
public class StartState implements State {
public void doAction(Context context) {
System.out.println("Player is in start state");
context.setState(this);
}
public String toString(){
return "Start State";
}
}
public class StopState implements State {
public void doAction(Context context) {
System.out.println("Player is in stop state");
context.setState(this);
}
public String toString(){
return "Stop State";
}
}
public class State_01 {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);
System.out.println(context.getState().toString());
StopState stopState = new StopState();
stopState.doAction(context);
System.out.println(context.getState().toString());
}
}
观察者模式
1.定义:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
2.介绍:
- 意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心;还有,当我们开车到交叉路口时,遇到红灯会停,遇到绿灯会行。这样的例子还有很多,例如,股票价格与股民、微信公众号与微信用户、气象局的天气预报与听众、小偷与警察等。
- 在软件世界也是这样,例如,Excel 中的数据与折线图、饼状图、柱状图之间的关系;MVC 模式中的模型与视图的关系;事件模型中的事件源与事件处理者。所有这些,如果用观察者模式来实现就非常方便。
3.实现:
//抽象目标
public abstract class Subject
{
protected List<Observer> observers=new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer)
{
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer)
{
observers.remove(observer);
}
public abstract void notifyObserver(); //通知观察者方法
}
//具体目标
public class ConcreteSubject extends Subject
{
public void notifyObserver()
{
System.out.println("具体目标发生改变...");
System.out.println("--------------");
for(Object obs:observers)
{
((Observer)obs).response();
}
}
}
//抽象观察者
public interface Observer
{
void response(); //反应
}
//具体观察者1
public class ConcreteObserver1 implements Observer
{
public void response()
{
System.out.println("具体观察者1作出反应!");
}
}
//具体观察者1
public class ConcreteObserver2 implements Observer
{
public void response()
{
System.out.println("具体观察者2作出反应!");
}
}
public class Observer_01 {
public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
ConcreteObserver1 concreteObserver1 = new ConcreteObserver1();
ConcreteObserver2 concreteObserver2 = new ConcreteObserver2();
concreteSubject.add(concreteObserver1);
concreteSubject.add(concreteObserver2);
concreteSubject.notifyObserver();
}
}
中介者模式
1.定义:中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
2.介绍:
-
在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的对象。例如,每个人必须记住他(她)所有朋友的电话;而且,朋友中如果有人的电话修改了,他(她)必须告诉其他所有的朋友修改,这叫作“牵一发而动全身”,非常复杂。
-
如果把这种“网状结构”改为“星形结构”的话,将大大降低它们之间的“耦合性”,这时只要找一个“中介者”就可以了。如前面所说的“每个人必须记住所有朋友电话”的问题,只要在网上建立一个每个朋友都可以访问的“通信录”就解决了。这样的例子还有很多,例如,你刚刚参加工作想租房,可以找“房屋中介”;或者,自己刚刚到一个陌生城市找工作,可以找“人才交流中心”帮忙。
-
在软件的开发过程中,这样的例子也很多,例如,在 MVC 框架中,控制器(C)就是模型(M)和视图(V)的中介者;还有大家常用的 QQ 聊天程序的“中介者”是 QQ 服务器。所有这些,都可以采用“中介者模式”来实现,它将大大降低对象之间的耦合性,提高系统的灵活性。
-
中介者模式又叫调停模式,它是迪米特法则的典型应用。
3.实现:
public class ChatRoom {
public static void showMessage(User user, String message){
System.out.println(new Date().toString()
+ " [" + user.getName() +"] : " + message);
}
}
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name){
this.name = name;
}
public void sendMessage(String message, User user){
ChatRoom.showMessage(user,message);
}
}
public class Mediator_01 {
public static void main(String[] args) {
User user = new User("小红");
User user1 = new User("小明");
user.sendMessage("How are you",user1);
user1.sendMessage("I'm fine",user);
}
}
迭代器模式
1.定义:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。迭代器模式是一种对象行为型模式.
2.介绍:
- 意图:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
- 关键代码:定义接口:hasNext, next。
- 应用实例:JAVA 中的 iterator。
3.实现:
//抽象聚合
public interface Aggregate
{
public void add(Object obj);
public void remove(Object obj);
public Iterator getIterator();
}
//具体聚合
public class ConcreteAggregate implements Aggregate
{
private List<Object> list=new ArrayList<Object>();
public void add(Object obj)
{
list.add(obj);
}
public void remove(Object obj)
{
list.remove(obj);
}
public Iterator getIterator()
{
return(new ConcreteIterator(list));
}
}
//抽象迭代器
public interface Iterator
{
Object first();
Object next();
boolean hasNext();
}
//具体迭代器
public class ConcreteIterator implements Iterator
{
private List<Object> list=null;
private int index=-1;
public ConcreteIterator(List<Object> list)
{
this.list=list;
}
public boolean hasNext()
{
if(index<list.size()-1)
{
return true;
}
else
{
return false;
}
}
public Object first()
{
index=0;
Object obj=list.get(index);;
return obj;
}
public Object next()
{
Object obj=null;
if(this.hasNext())
{
obj=list.get(++index);
}
return obj;
}
}
public class Iterator_01 {
public static void main(String[] args) {
ConcreteAggregate concreteAggregate = new ConcreteAggregate();
concreteAggregate.add(1);
concreteAggregate.add(2);
concreteAggregate.add(3);
Iterator iterator = concreteAggregate.getIterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
访问者模式
1.定义:在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
2.介绍:
- 意图:主要将数据结构与数据操作分离。
- 应用实例:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。
3.实现:
//抽象元素类
public interface Element
{
void accept(Visitor visitor);
}
//具体元素A类
public class ConcreteElementA implements Element
{
public void accept(Visitor visitor)
{
visitor.visit(this);
}
public String operationA()
{
return "具体元素A的操作。";
}
}
//具体元素B类
public class ConcreteElementB implements Element
{
public void accept(Visitor visitor)
{
visitor.visit(this);
}
public String operationB()
{
return "具体元素B的操作。";
}
}
//抽象访问者
public interface Visitor
{
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
//具体访问者A类
public class ConcreteVisitorA implements Visitor
{
public void visit(ConcreteElementA element)
{
System.out.println("具体访问者A访问-->"+element.operationA());
}
public void visit(ConcreteElementB element)
{
System.out.println("具体访问者A访问-->"+element.operationB());
}
}
//具体访问者B类
public class ConcreteVisitorB implements Visitor
{
public void visit(ConcreteElementA element)
{
System.out.println("具体访问者B访问-->"+element.operationA());
}
public void visit(ConcreteElementB element)
{
System.out.println("具体访问者B访问-->"+element.operationB());
}
}
//对象结构角色
public class ObjectStructure
{
private List<Element> list=new ArrayList<Element>();
public void accept(Visitor visitor)
{
Iterator<Element> i=list.iterator();
while(i.hasNext())
{
((Element) i.next()).accept(visitor);
}
}
public void add(Element element)
{
list.add(element);
}
public void remove(Element element)
{
list.remove(element);
}
}
public class Visitor_01 {
public static void main(String[] args) {
ConcreteElementA concreteElementA = new ConcreteElementA();
ConcreteElementB concreteElementB = new ConcreteElementB();
ObjectStructure objectStructure = new ObjectStructure();
objectStructure.add(concreteElementA);
objectStructure.add(concreteElementB);
ConcreteVisitorA concreteVisitorA = new ConcreteVisitorA();
ConcreteVisitorB concreteVisitorB = new ConcreteVisitorB();
objectStructure.accept(concreteVisitorA);
objectStructure.accept(concreteVisitorB);
}
}
备忘录模式
1.定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。
2.介绍:
- 备忘录模式是一种对象行为型模式,其主要优点如下。
- 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
- 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
- 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
3.实现:
//备忘录
public class Memento
{
private String state;
public Memento(String state)
{
this.state=state;
}
public void setState(String state)
{
this.state=state;
}
public String getState()
{
return state;
}
}
//管理者
public class Caretaker
{
private Memento memento;
public void setMemento(Memento m)
{
memento=m;
}
public Memento getMemento()
{
return memento;
}
}
//发起人
public class Originator
{
private String state;
public void setState(String state)
{
this.state=state;
}
public String getState()
{
return state;
}
public Memento createMemento()
{
return new Memento(state);
}
public void restoreMemento(Memento m)
{
this.setState(m.getState());
}
}
public class Memento_01 {
public static void main(String[] args) {
Originator or=new Originator();
Caretaker cr=new Caretaker();
or.setState("S0");
System.out.println("初始状态:"+or.getState());
cr.setMemento(or.createMemento()); //保存状态
or.setState("S1");
System.out.println("新的状态:"+or.getState());
or.restoreMemento(cr.getMemento()); //恢复状态
System.out.println("恢复状态:"+or.getState());
}
}
解释器模式
1.定义:解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
2.介绍:
- 解释器模式是一种类行为型模式,其主要优点如下。
- 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
- 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。
3.实现:
//抽象表达式类
public interface Expression
{
public boolean interpret(String info);
}
//非终结符表达式类
public class AndExpression implements Expression
{
private Expression city=null;
private Expression person=null;
public AndExpression(Expression city,Expression person)
{
this.city=city;
this.person=person;
}
public boolean interpret(String info)
{
String s[]=info.split("的");
return city.interpret(s[0])&&person.interpret(s[1]);
}
}
//终结符表达式类
public class TerminalExpression implements Expression
{
private Set<String> set= new HashSet<String>();
public TerminalExpression(String[] data)
{
for(int i=0;i<data.length;i++)set.add(data[i]);
}
public boolean interpret(String info)
{
if(set.contains(info))
{
return true;
}
return false;
}
}
//环境类
public class Context
{
private String[] citys={"韶关","广州"};
private String[] persons={"老人","妇女","儿童"};
private Expression cityPerson;
public Context()
{
Expression city=new TerminalExpression(citys);
Expression person=new TerminalExpression(persons);
cityPerson=new AndExpression(city,person);
}
public void freeRide(String info)
{
boolean ok=cityPerson.interpret(info);
if(ok) System.out.println("您是"+info+",您本次乘车免费!");
else System.out.println(info+",您不是免费人员,本次乘车扣费2元!");
}
}
public class Interpreter_01 {
public static void main(String[] args) {
Context context = new Context();
context.freeRide("韶关的老人");
}
}