java设计模式案例及使用
java设计模式
创建者模式
单例设计模式
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {private Singleton() {}private static Singleton single=null;//静态工厂方法 public static Singleton getInstance() {if (single == null) { single = new Singleton();} return single;}
}
//静态内部类方式
public class Singleton { private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return LazyHolder.INSTANCE; }
}//饿汉式单例类.在类初始化时,已经自行实例化
public class Singleton1 {private Singleton1() {}private static final Singleton1 single = new Singleton1();//静态工厂方法 public static Singleton1 getInstance() {return single;}
}
饿汉式和懒汉式区别
从名字上来说,饿汉和懒汉,
饿汉就是类一旦加载,就把单例初始化完成,保证getInstance的时候,单例是已经存在的了,
而懒汉比较懒,只有当调用getInstance的时候,才回去初始化这个单例。
1、资源加载和性能:
饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,
而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。
2、线程安全:
饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题,
懒汉式本身是非线程安全的,为了实现线程安全有几种写法,这三种实现在资源加载和性能方面有些区别。
简单工厂模式
案例:现在有一个一个coffee抽象类,一个美国咖啡类,一个拿铁咖啡类,一个咖啡店类
public abstract class coffee {public void addSugar(){System.out.println("add sugar");}public void addMilk(){System.out.println("add milk");}public abstract String getName();
}public class AmericanCoffee extends coffee{@Overridepublic String getName() {return "美国咖啡";}
}public class lettenCoffee extends coffee {@Overridepublic String getName() {return "拿铁咖啡";}
}public class coffeeFactory {public static coffee createCoffee(String type){coffee coffee=null;if("American".equals(type)){coffee=new AmericanCoffee();}else if("letten".equals(type)){coffee=new lettenCoffee();}else{throw new RuntimeException("没有其他咖啡");}return coffee;}
}public class coffeeStore {public static coffee getCoffee(String type){coffee coffee = coffeeFactory.createCoffee(type);coffee.addMilk();coffee.addSugar();return coffee;}}public class client {public static void main(String[] args) {coffee american = coffeeStore.getCoffee("American");System.out.println(american.getName());}}
但是这段代码 虽然解决 了咖啡店类与咖啡之间的耦合,但是咖啡店类与咖啡工厂类产生了耦合。而且要想再扩充咖啡,就要修改源代码,这样违背了开闭原则。
解决办法: 使用 工厂方法模式
工厂方法模式
:定义一个用于创建对象的接口,让子类决定实例化哪个对象类产品,工厂方法使一个产品的实例化延迟到其工厂类的子类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DSjZJ05M-1630317263386)(C:\Users\YD\AppData\Roaming\Typora\typora-user-images\image-20210220213515730.png)]
public interface coffeeFactory {coffee createCoffee();
}public class LattenCoffeeFactory implements coffeeFactory {@Overridepublic coffee createCoffee() {return new lettenCoffee();}
}public class AmericanCoffeeFactory implements coffeeFactory {@Overridepublic coffee createCoffee() {return new AmericanCoffee();}
}public class AmericanCoffee extends coffee{@Overridepublic String getName() {return "美国咖啡";}
}public class lettenCoffee extends coffee {@Overridepublic String getName() {return "拿铁咖啡";}
}public class coffeeStore {private coffeeFactory coffeeFactory ;public void setCoffeeFactory(coffeeFactory coffeeFactory) {this.coffeeFactory = coffeeFactory;}public coffee getCoffee(){coffee coffee = coffeeFactory.createCoffee();coffee.addMilk();coffee.addSugar();return coffee;}}public class main {public static void main(String[] args) {coffeeStore coffeeStore =new coffeeStore() ;coffeeFactory coffeeFactory =new AmericanCoffeeFactory();coffeeStore.setCoffeeFactory(coffeeFactory);coffee coffee = coffeeStore.getCoffee();System.out.println(coffee.getName());}}
优点:
- 用户只需要知道具体的工厂名字就可得到所要得产品,无须知道产品得具体创建过程。
- 在系统增加新得产品时只需要添加具体得产品和具体得工厂实现类,无须对原工厂类进行修改,完全遵守开闭原则。
缺点:
每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的负责度。
抽象工厂模式
: 抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。
案例 :宝马320系列使用空调型号A和发动机型号A,而宝马230系列使用空调型号B和发动机型号B,那么使用抽象工厂模式,在为320系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号A。
//发动机以及型号
public interface Engine {
} public class EngineA extends Engine{ public EngineA(){ System.out.println("制造-->EngineA"); }
}
public class EngineBextends Engine{ public EngineB(){ System.out.println("制造-->EngineB"); }
}
//空调以及型号
public interface Aircondition {
} public class AirconditionA extends Aircondition{ public AirconditionA(){ System.out.println("制造-->AirconditionA"); }
} public class AirconditionB extends Aircondition{ public AirconditionB(){ System.out.println("制造-->AirconditionB"); }
}
//创建工厂的接口
public interface AbstractFactory { //制造发动机public Engine createEngine();//制造空调 public Aircondition createAircondition();
}
//为宝马320系列生产配件
public class FactoryBMW320 implements AbstractFactory{ @Override public Engine createEngine() { return new EngineA(); } @Override public Aircondition createAircondition() { return new AirconditionA(); }
}
//宝马523系列
public class FactoryBMW523 implements AbstractFactory { @Override public Engine createEngine() { return new EngineB(); } @Override public Aircondition createAircondition() { return new AirconditionB(); }
}
优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
当产品族中需要增加一个新的产品时,所有的工厂类都需要修改。
模式扩展
工厂类使用配置文件反射来创建对象类
案例:咖啡店
public class AmericanCoffee extends coffee {@Overridepublic String getName() {return "美国咖啡";}
}public abstract class coffee {public void addSugar(){System.out.println("add sugar");}public void addMilk(){System.out.println("add milk");}public abstract String getName();
}import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Properties;
import java.util.Set;public class coffeeFactory {private static HashMap<String,Object> map= new HashMap<String, Object>();static{try {Properties p= new Properties() ;InputStream in = coffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");p.load(in);Set<Object> keys = p.keySet();for( Object key:keys){String className=p.getProperty((String) key);Class<?> clazz = Class.forName(className);coffee coffee=(coffee)clazz.newInstance();map.put((String)key,coffee);}} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}public static coffee createFactory(String name){return (coffee) map.get(name);}
}public class lettenCoffee extends coffee {@Overridepublic String getName() {return "拿铁咖啡";}
}//bean.properties 中写入key:name ,value:创建对象的全类名
American=AmericanCoffee
Latte=lettenCoffee//测试
public class client {public static void main(String[] args) {coffee coffee = coffeeFactory.createFactory("American");System.out.println(coffee);}
}
原型模式
public class PrototypeClass implements Cloneable{//覆写父类Object方法@Overridepublic PrototypeClass clone(){PrototypeClass prototypeClass = null;try {prototypeClass = (PrototypeClass)super.clone();} catch (CloneNotSupportedException e) {//异常处理}return prototypeClass;}
}
原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的
原型模式注意事项:
- 当使用克隆来创建对象的时候,构造函数不会被执行。
- 原型模式其实就是一种拷贝机制,分为浅拷贝和深拷贝两种机制。
浅拷贝:
public class Thing implements Cloneable{//定义一个私有变量private ArrayList<String> arrayList = new ArrayList<String>();@Overridepublic Thing clone(){Thing thing=null;try {thing = (Thing)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return thing;}//设置HashMap的值public void setValue(String value){this.arrayList.add(value);}//取得arrayList的值public ArrayList<String> getValue(){return this.arrayList;}
}//测试类
public class Client {public static void main(String[] args) {//产生一个对象Thing thing = new Thing();//设置一个值thing.setValue("张三");//拷贝一个对象Thing cloneThing = thing.clone();cloneThing.setValue("李四");System.out.println(thing.getValue());}
因为Java做了一个偷懒的拷贝动作,Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。确实是非常浅,两个对象共享了一个私有变量,你改我改大家都能改,是一种非常不安全的方式。
深拷贝:
public class Thing implements Cloneable{//定义一个私有变量private ArrayList<String> arrayList = new ArrayList<String>();@Overridepublic Thing clone(){Thing thing=null;try {thing = (Thing)super.clone();thing.arrayList = (ArrayList<String>)this.arrayList.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return thing;}
}
要实现深拷贝,则需要对对私有的类变量进行独立的拷贝。这样拷贝的对象和原对象没有任何关系,你修改你的,我修改我的。实际项目中用这种深拷贝机制。
注意:要使用clone方法,成员变量上不能使用final修饰
建造者模式
建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出 来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们, 用户不需要知道内部的具体构建细节。
建造者模式的四个角色 :
Product(产品角色): 一个具体的产品对象。
Builder(抽象建造者): 创建一个 Product 对象的各个部件指定的 接口**/**抽象类。
ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
Director(指挥者): 构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作 用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
//product
public class house {private String detail;public String getDetail() {return detail;
}public void setDetail(String detail) {this.detail = detail;
}
}//builder 接口
public abstract class builder {private house h =new house();abstract void start();abstract void mid();abstract void over();public house getHouse() {return h;}
}//concrectBuilder继承类,代表某一类房子
public class commonhouse extends builder {@Overridevoid start() {System.out.println("打地基20天");}@Overridevoid mid() {System.out.println("砌房子40天");}@Overridevoid over() {System.out.println("完工收拾10天"); }
}//director类:指挥类,只要有不同的实现都可以用它来指挥。
public class buiderDirect {private builder b;
public buiderDirect(builder b) {this.b=b;
}
public house creatHouse() {b.start();b.mid();b.over();return b.getHouse();
}
}//客户测试
public static void main(String[] args) {commonhouse c=new commonhouse();buiderDirect b=new buiderDirect(c);house house = b.creatHouse();
}
}
创建者模式扩展:
package builderdemo2;public class phone {private String cpu;private String mainBroad;private String memory;private String screen;private phone(Builder builder){this.cpu=builder.cpu;this.mainBroad=builder.mainBroad;this.memory=builder.memory;this.screen=builder.screen;}@Overridepublic String toString() {return "phone{" +"cpu='" + cpu + '\'' +", mainBroad='" + mainBroad + '\'' +", memory='" + memory + '\'' +", screen='" + screen + '\'' +'}';}public static final class Builder{private String cpu;private String mainBroad;private String memory;private String screen;public Builder cpu(String cpu){this.cpu=cpu;return this;}public Builder mainBroad(String mainBroad){this.mainBroad=mainBroad;return this;}public Builder memory(String memory){this.memory=memory;return this;}public Builder screen(String screen){this.screen=screen;return this;}public phone build(){return new phone(this);}}
}
结构型模式
代理模式
:代理根据代理类的产生方式和时机分为静态代理和动态代理两种。代理类不仅可以有效的将具体的实现与调用方进行解耦,通过面向接口进行编码完全将具体的实现隐藏在内部,而且还可以在符合开闭原则的前提下,对目标类进行进一步的增强。典型地,Spring AOP 是对JDK动态代理的经典应用。
所谓静态代理,其实质是自己手写(或者用工具生成)代理类,也就是在程序运行前就已经存在的编译好的代理类
动态代理可以在程序运行期间根据需要动态的创建代理类及其实例来完成具体的功能
代理模式包含如下几个角色:
- 客户端:客户端面向接口编程,使用代理角色完成某项功能。
- 抽象主题:一般实现为接口,是对(被代理对象的)行为的抽象。
- 被代理角色(目标类):直接实现上述接口,是抽象主题的具体实现。
- 代理角色(代理类):实现上述接口,是对被代理角色的增强。
静态代理
//抽象主题
public interface movie {void play();
}
//被代理类
public class RealMovie implements movie{public void play() {System.out.println("正在播放电影.........");}
}//代理类
public class Cinema implements movie {private RealMovie realMovie ;public void play() {start();realMovie.play();end();}public Cinema(RealMovie realMovie) {this.realMovie = realMovie;}public void start(){System.out.println("电影播放开始!");}public void end(){System.out.println("电影播放结束!");}
}
//客户使用
public class Client {public static void main(String[] args) {RealMovie realMovie =new RealMovie();movie cinema=new Cinema(realMovie);cinema.play();}
}
动态代理
Jdk动态代理:
//抽象主题
public interface movie {void play();
}//被代理类
public class RealMovie implements movie {public void play() {System.out.println("正在播放电影.........");}
}//调用代理对象的工厂
public class ProxyFactory {private RealMovie realMovie =new RealMovie();public movie CreateProxy(){/*newProxyInstance()方法有三个参数:1.类加载器2.被代理对象的接口3.InvocationHandler接口的实现类*//*invoke方法的参数:1.跟 movie对象是一致2.对接口中方法进行封装的method3.调用方法的实际参数*/movie movie=(JDKProxy.movie) Proxy.newProxyInstance(realMovie.getClass().getClassLoader(),realMovie.getClass().getInterfaces(),new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("执行前!");Object invoke = method.invoke(realMovie, args);System.out.println("执行后!");return invoke;}});return movie;}
}
//客户使用
public class Client {public static void main(String[] args) {ProxyFactory proxyFactory =new ProxyFactory() ;movie movie = proxyFactory.CreateProxy();movie.play();}
}
//调用代理对象类
public class ProxyFactory2 implements InvocationHandler {private movie realMovie;public void setRealMovie(movie realMovie) {this.realMovie = realMovie;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("执行前!");Object invoke = method.invoke(realMovie, args);System.out.println("执行后!");return invoke;}}
//客户调用,还是第一种好用
public class Client {public static void main(String[] args) {movie movie =new RealMovie();ProxyFactory2 proxyFactory2 = new ProxyFactory2();proxyFactory2.setRealMovie(movie);movie ProxyMovie =(movie) Proxy.newProxyInstance(movie.getClass().getClassLoader(),movie.getClass().getInterfaces(),proxyFactory2);ProxyMovie.play();}
}
cglib 动态代理
首先需要导入cglib的jar包:cglib-nodep-2.1_3.jar
public interface PersonService {public String savePerson();public void updatePerson();public void deletePerson();}public class PersonServiceImpl implements PersonService{@Overridepublic String savePerson() {System.out.println("添加");return "保存成功!";}@Overridepublic void updatePerson() {System.out.println("修改");}@Overridepublic void deletePerson() {System.out.println("删除");}}public class MyTransaction {public void beginTransaction(){System.out.println("开启事务 ");}public void commit(){System.out.println("提交事务");}
}public class PersonServiceInterceptor implements MethodInterceptor{//目标类private Object target;//增强类private MyTransaction myTransaction;//构造函数注入目标类和增强类public PersonServiceInterceptor(Object target,MyTransaction myTransaction){this.target = target;this.myTransaction = myTransaction;}public Object createProxy(){Enhancer enhancer = new Enhancer();enhancer.setCallback(this);enhancer.setSuperclass(this.target.getClass());return enhancer.create();}@Overridepublic Object intercept(Object arg0, Method arg1, Object[] arg2,MethodProxy arg3) throws Throwable {myTransaction.beginTransaction();Object returnValue = arg1.invoke(this.target, arg2);myTransaction.commit();return returnValue;}}public class ProxyTest {@Testpublic void test(){Object target = new PersonServiceImpl();MyTransaction myTransaction = new MyTransaction();PersonServiceInterceptor interceptor = new PersonServiceInterceptor(target, myTransaction);PersonService personService =(PersonService) interceptor.createProxy();String returnValue = (String)personService.savePerson();System.out.println(returnValue);}
适配器模式
:将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适用场景:
1、已经存在的类的接口不符合我们的需求;
2、创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;
3、在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。
其实现方式主要有两种:
1.类的适配器模式(采用继承实现)
2.对象适配器(采用对象组合方式实现)
类的适配器模式
:被适配的类必须是实现一个接口
案例:现在有两个接口一个是sd卡,一个是tf卡,而computer类只能调用sd卡,所以需要适配器类去适配sd卡
//sd卡接口
public interface sdCard {String readSD();void writeSD(String msg);
}
//tf卡接口
public interface TFCard {String readTF();void writeTF(String msg);
}
//sd卡实现类
public class sdCardImpl implements sdCard{public String readSD() {return "read word : sdCard";}public void writeSD(String msg) {System.out.println("write sd card");}
}//tf卡实现类
public class TFCardImpl implements TFCard {public String readTF() {return "read word : TF card";}public void writeTF(String msg) {System.out.println("write word : tf card");}
}//电脑类(只能调用sd卡接口及实现类)
public class computer {public void readCard(sdCard sdCard) {System.out.println(sdCard.readSD());}}//适配器类去适配sd卡
public class adapterService extends TFCardImpl implements sdCard {public String readSD() {System.out.println("adapter service run...");return readTF();}public void writeSD(String msg) {writeTF(msg);}
}//这样就可以调用tf卡去兼容sd卡了
public class Client {public static void main(String[] args) {computer computer=new computer() ;computer.readCard(new sdCardImpl());System.out.println("==============");computer.readCard(new adapterService());}
}
对象适配器模式
//对上面的适配器类进行修改
public class adapterService implements sdCard {private TFCard readTF ;public adapterService(TFCard readTF) {this.readTF = readTF;}public String readSD() {System.out.println("adapter service run...");return readTF.readTF();}public void writeSD(String msg) {readTF.writeTF(msg);}
}
//客户类调用
public class Client {public static void main(String[] args) {computer computer=new computer() ;computer.readCard(new sdCardImpl());System.out.println("==============");computer.readCard(new adapterService(new TFCardImpl()));}
}
装饰者模式
:装饰模式的设计理念主要是以对客户端透明的方式动态扩展对象的功能,是继承关系的一个替代(继承会产生大量的子类,而且代码有冗余)。装饰模式可以在不创造更多子类的情况下,将对象的功能加以扩展。装饰模式把客户端的调用委派到被装饰类。装饰模式的关键在于这种扩展完全是透明的(装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型),装饰模式的应用在java的I/O流中最为显著。
角色:
- 抽象构件角色(Component):通常是一个抽象类或者一个接口,定义了一系列方法,方法的实现可以由子类实现或者自己实现。通常不会直接使用该类,而是通过继承该类或者实现该接口来实现特定的功能。(例如,对于动物类,有一个抽象方法输出所有的功能,基本功能包括:呼吸,觅食,睡觉等等)
- 具体构件角色(Concrete Component):是Component的子类,实现了对应的方法,它就是那个被装饰的类。(具体构建角色可以建立很多个,例如狗,猫,鸟等等,如果是狗,我们可以装饰一些吼叫的功能,吃肉的功能;鸟可以装饰一些飞行的功能,带有翅膀的功能等等。当然这些需要在具体装饰角色中去具体定义)
- 装饰角色(Decorator):是Component的子类,它是具体装饰角色共同实现的抽象类(也可以是接口),并且持有一个Component类型的对象引用,它的主要作用就是把客户端的调用委派到被装饰类。
- 具体装饰角色(Concrete Decorator):它是具体的装饰类,是Decorator的子类,当然也是Component的子类。它主要就是定义具体的装饰功能,例如上面说的,对于鸟这个具体构建角色而言,除了具备抽象构件角色基本的功能,它还具有一些飞行的功能,带翅膀的功能。那么我们可以把这两个功能定义成一个具体装饰角色1,对于狗这个具体构件角色而言,我们可以把吼叫,吃肉这两个功能定义成一个具体装饰角色2,这样,如果我们再定义一个狼这样的具体构件角色的时候,就可以直接用具体装饰角色2来进行装饰。
案例:
饭店有卖炒饭炒面,而客户可以在买炒饭炒面的同时加鸡蛋或者培根,如果是使用传统的继承关系去实现会产生很大的冗余,所以选择用修饰者模式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bPXU3i31-1630317263390)(C:\Users\YD\AppData\Roaming\Typora\typora-user-images\image-20210227190221528.png)]
// 抽象构件角色类
public abstract class FastFood {private float price;private String desc;public FastFood(float price, String desc) {this.price = price;this.desc = desc;}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}public abstract float cost();
}//具体构件角色类
public class FastRice extends FastFood {public FastRice() {super(10,"炒饭");}public float cost() {return getPrice();}
}//具体构件角色类
public class FastNoodle extends FastFood {public FastNoodle(float price, String desc) {super(12, "炒面");}public float cost() {return getPrice();}
}//修饰角色类
public abstract class Garnish extends FastFood {private FastFood fastFood ;public Garnish(FastFood fastFood , float price, String desc) {super(price, desc);this.fastFood=fastFood;}public FastFood getFastFood() {return fastFood;}public void setFastFood(FastFood fastFood) {this.fastFood = fastFood;}}//具体修饰角色类
public class Egg extends Garnish {public Egg(FastFood fastFood) {super(fastFood, 1, "加鸡蛋");}public float cost() {return super.getPrice()+getFastFood().cost();}@Overridepublic String getDesc() {return super.getDesc()+getFastFood().getDesc();}
}//具体修饰角色类
public class Bacon extends Garnish {public Bacon(FastFood fastFood) {super(fastFood, 2, "加培根");}public float cost() {return super.getPrice()+getFastFood().cost();}@Overridepublic String getDesc() {return super.getDesc()+getFastFood().getDesc();}
}//客户类 调用效果
public class Client {public static void main(String[] args) {FastFood fastFood =new FastRice();System.out.println(fastFood.getDesc()+" "+fastFood.cost());System.out.println("==============");fastFood=new Egg(fastFood);System.out.println(fastFood.getDesc()+" "+fastFood.cost());}
}
桥接模式
:将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式(Handle and Body)模式或接口(Interface)模式。
角色:
- 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。在抽象对象里面的方法,需要调用实现部分的对象来完成。
- 修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。添加跟实际业务相关的方法,这些方法的实现通常会使用Abstraction中定义的方法,也可能需要调用实现部分的对象来完成。
- 实现化(Implementor)角色:定义实现部分的接口,这个接口不用和Abstraction里面的方法一致,通常是由Implementor接口提供基本的操作,而Abstraction里面定义的是基于这些基本操作的业务方法,也就是说Abstraction定义了基于这些基本操作的较高层次的操作。
- 具体实现化(Concrete Implementor)角色:真正实现Implementor接口的对象。
案例(在不同的操作系统上部分不同的类型视频)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kUMaz3wC-1630317263398)(C:\Users\YD\AppData\Roaming\Typora\typora-user-images\image-20210228201037972.png)]
//视频类型接口(实现化角色)
public interface video {void decode(String fileName);
}
//具体实现化角色
public class RMVVideo implements video {public void decode(String fileName) {System.out.println("rmv video :"+fileName);}
}
//具体实现化角色
public class AVIVideo implements video {public void decode(String fileName) {System.out.println("avi video :"+ fileName);}
}public abstract class OperatingSystem {private video video ;public OperatingSystem(Bridge.video video) {this.video = video;}public Bridge.video getVideo() {return video;}public void setVideo(Bridge.video video) {this.video = video;}public abstract void play(String fileName);
}public class windows extends OperatingSystem{public windows(Bridge.video video) {super(video);}public void play(String fileName) {getVideo().decode(fileName);}
}public class mac extends OperatingSystem {public mac(Bridge.video video) {super(video);}public void play(String fileName) {getVideo().decode(fileName);}
}public class Client {public static void main(String[] args) {video video =new RMVVideo();OperatingSystem system=new windows(video);system.play("剑网三");}
}
外观模式
:他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式属于结构性模式。为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。
角色
- 门面角色:外观模式的核心。它被客户角色调用,它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合。
- 子系统角色:实现了子系统的功能。它对客户角色和Facade时未知的。它内部可以有系统内的相互交互,也可以由供外界调用的接口。
- 客户角色:通过调用Facede来完成要实现的功能。
//子系统角色
public class Cpu {public void start(){System.out.println("cpu has started");}public void stop(){System.out.println("cpu has started");}
}
//子系统角色
public class Disk {public void start(){System.out.println("disk has started");}public void stop(){System.out.println("disk has started");}
}
//子系统角色
public class Memory {public void start(){System.out.println("memory has started");}public void stop(){System.out.println("memory has started");}
}//门面系统角色
public class ComputorFacade {private Cpu cpu;private Disk disk;private Memory memory;public ComputorFacade() {this.cpu = new Cpu();this.disk = new Disk();this.memory = new Memory();}public void start(){System.out.println("Computor start begin");cpu.start();disk.start();memory.start();System.out.println("Computor start end");}public void stop(){System.out.println("Computor stop begin");cpu.stop();disk.stop();memory.stop();System.out.println("Computor stop end");}
}//客户类
public class FacadeTest {public static void main(String[] args) {ComputorFacade computorFacade = new ComputorFacade();computorFacade.start();System.out.println("========================");computorFacade.stop();}
}
使用场景
- 为复杂的模块或子系统提供外界访问的模块;
- 子系统相互独立;
- 在层析结构中,可以使用外观模式定义系统的每一层的入口。
组合模式
:组合模式使用户对单个对象和组合对象的使用具有一致性。
屏蔽了容器对象与单个对象在使用时的差异,为客户提供统一的操作接口,从而降低客户代码与被调用对象的耦合关系,方便系统维护与扩展。
角色
- Component 抽象的组件对象,为参与组合的对象声明接口,让客户端可以通过这个接口来访问和管理整个对象结构,可以定义一些默认的行为或属性。
- Leaf 叶子节点对象,其下不再包含其它的子节点,也就是遍历的最小单位。
- Composite 组合对象,通常会存储子组件,形成一个树形结构。
案例(文件目录)
//抽象的组件对象
public abstract class Component {protected String name;protected int level;public Component(String name, int level) {this.name = name;this.level = level;}public void addChild(Component component){throw new RuntimeException("已经是根节点了!");}public void getChild(int index){throw new RuntimeException("已经是根节点了!");}public void removeChild(int index){throw new RuntimeException("已经是根节点了!");}public abstract void printStruct();}//Composite组合对象
public class Menu extends Component {private List<Component> components =new ArrayList<Component>();public Menu(String name, int level) {super(name, level);}@Overridepublic void addChild(Component component) {components.add(component);}@Overridepublic void getChild(int index) {components.get(index);}@Overridepublic void removeChild(int index) {components.remove(index);}public void printStruct() {System.out.println(" "+super.level+super.name);for (Component component : components) {component.printStruct();}}
}//叶子节点对象
public class Leaf extends Component{public Leaf(String name, int level) {super(name, level);}public void printStruct() {System.out.println(" "+super.level+super.name);}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n55WCth5-1630317263402)(C:\Users\YD\AppData\Roaming\Typora\typora-user-images\image-20210301160244216.png)]
享元模式
:运用共享技术来有效地支持大量细粒度对象地复用,它通过共享已经存在地对象来大幅度减少选哟创建的数量,避免大量相似对象的开销,从而提高系统的利用率。
1.内部状态,即不会随着环境的改变而改变的可共享部分。
2.外部状态,指随环境改变而改变的不可以共享的部分。享元模式的实现要领就是区别应用中的这两种状态,并将外部状态外部化。
角色:
1、Flyweight (享元抽象类):一般是接口或者抽象类,定义了享元类的公共方法。这些方法可以分享内部状态的数据,也可以调用这些方法修改外部状态。
2、ConcreteFlyweight(具体享元类):具体享元类实现了抽象享元类的方法,为享元对象开辟了内存空间来保存享元对象的内部数据,同时可以通过和单例模式结合只创建一个享元对象。
3、UnshareConcreteFlyweight(非共具体享元类):并不是所有的享元类都需要被共享的有的享元类就不要被共享,可以通过享元类来实例一个非共享享元对象。
4、Flyweight(享元工厂类):享元工厂类创建并且管理享元类,享元工厂类针对享元类来进行编程,通过提供一个享元池来进行享元对象的管理。一般享元池设计成键值对,或者其他的存储结构来存储。当客户端进行享元对象的请求时,如果享元池中有对应的享元对象则直接返回对应的对象,否则工厂类创建对应的享元对象并保存到享元池。
案例(俄罗斯方块)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MJ92BUHq-1630317263404)(C:\Users\YD\AppData\Roaming\Typora\typora-user-images\image-20210301174035138.png)]
//享元抽象类
public abstract class AbstractBox {public abstract String getShape();public void display(String color){System.out.println("图型:"+getShape()+",颜色:"+color);}
}//具体享元类
public class IBox extends AbstractBox {public String getShape() {return "I";}
}//具体享元类
public class LBox extends AbstractBox{public String getShape() {return "L";}
}//具体享元类
public class OBox extends AbstractBox{public String getShape() {return "O";}
}//享元工厂类
public class BoxFactory {private HashMap<String,AbstractBox> abstractBoxHashMap;private BoxFactory(){abstractBoxHashMap=new HashMap<String, AbstractBox>();abstractBoxHashMap.put("L",new LBox());abstractBoxHashMap.put("I",new IBox());abstractBoxHashMap.put("O",new OBox());}public static BoxFactory getInstance(){return factory;}private static BoxFactory factory=new BoxFactory();public AbstractBox getShape(String name){return abstractBoxHashMap.get(name);}
}
jdk源码解析
Integer a = 127;
Integer b=127;
System.out.println(a==b);Integer x =128;
Integer y =128;
System.out.println(x==y);result:
true
false
其中的原因就是jdk的Integer类中使用了享元模式设计,在初始化的时候创建 [-128,127] 的Integer对象,不在范围内则在调用时创建新的对象
行为型模式
模板方法模式
:模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。
角色:
抽象模板(Abstract Template)角色有如下责任:
■ 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。
■ 定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
具体模板(Concrete Template)角色又如下责任:
■ 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。
■ 每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
//抽象模板角色
public abstract class Account {/*** 模板方法,计算利息数额* @return 返回利息数额*/public final double calculateInterest(){double interestRate = doCalculateInterestRate();String accountType = doCalculateAccountType();double amount = calculateAmount(accountType);return amount * interestRate;}/*** 基本方法留给子类实现*/protected abstract String doCalculateAccountType();/*** 基本方法留给子类实现*/protected abstract double doCalculateInterestRate();/*** 基本方法,已经实现*/private double calculateAmount(String accountType){/*** 省略相关的业务逻辑*/return 7243.00;}
}//具体模板角色
public class MoneyMarketAccount extends Account {@Overrideprotected String doCalculateAccountType() {return "Money Market";}@Overrideprotected double doCalculateInterestRate() {return 0.045;}}
//客户类
public class Client {public static void main(String[] args) {Account account = new MoneyMarketAccount();System.out.println("货币市场账号的利息数额为:" + account.calculateInterest());account = new CDAccount();System.out.println("定期账号的利息数额为:" + account.calculateInterest());}}
模板方法模式在jdk中的应用
使用过Servlet的人都清楚,除了要在web.xml做相应的配置外,还需继承一个叫HttpServlet的抽象类。HttpService类提供了一个service()方法,这个方法调用七个do方法中的一个或几个,完成对客户端调用的响应。这些do方法需要由HttpServlet的具体子类提供,因此这是典型的模板方法模式。
protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {String method = req.getMethod();if (method.equals(METHOD_GET)) {long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logicdoGet(req, resp);} else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);if (ifModifiedSince < (lastModified / 1000 * 1000)) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be lessmaybeSetLastModified(resp, lastModified);doGet(req, resp);} else {resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}}} else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals(METHOD_POST)) {doPost(req, resp);} else if (method.equals(METHOD_PUT)) {doPut(req, resp); } else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {//// Note that this means NO servlet supports whatever// method was requested, anywhere on this server.//String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}
从上面的类图可以看出,TestServlet类是HttpServlet类的子类,并且置换掉了父类的两个方法:doGet()和doPost()。
public class TestServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("using the GET method");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("using the POST method");}}
从上面的例子可以看出这是一个典型的模板方法模式。
HttpServlet担任抽象模板角色
模板方法:由service()方法担任。
基本方法:由doPost()、doGet()等方法担任。
TestServlet担任具体模板角色
TestServlet置换掉了父类HttpServlet中七个基本方法中的其中两个,分别是doGet()和doPost()。
策略模式
背景:
在软件开发中常常遇到这种情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。如查找、排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…或者case等条件判断语句来进行选择。
这两种实现方法我们都可以称之为硬编码,如果需要增加一种新的查找算法,需要修改封装算法类的源代码;更换查找算法,也需要修改客户端调用代码。在这个算法类中封装了大量查找算法,该类代码将较复杂,维护较为困难。如果我们将这些策略包含在客户端,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重。
角色:
- 环境类(Context):用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Strategy访问它的数据。
- 抽象策略类(Strategy):定义所有支持的算法的公共接口。 Context使用这个接口来调用某ConcreteStrategy定义的算法。
- 具体策略类(ConcreteStrategy):以Strategy接口实现某具体算法。
案例
场景如下,刘备要到江东娶老婆了,走之前诸葛亮给赵云三个锦囊妙计,说是按天机拆开能解决棘手问题。场景中出现三个要素:三个妙计(具体策略类)、一个锦囊(环境类)、赵云(调用者)。
//抽象策略类
public interface Strategy {public void operate();
}//具体策略类
public class BackDoor implements Strategy {@Overridepublic void operate() {System.out.println("找乔国老帮忙,让吴国太给孙权施加压力,使孙权不能杀刘备");}
}//具体策略类
public class GivenGreenLight implements IStrategy {@Overridepublic void operate() {System.out.println("求吴国太开个绿灯,放行");}
}
//具体策略类
public class BlackEnemy implements IStrategy {@Overridepublic void operate() {System.out.println("孙夫人断后,挡住追兵");}
}
//环境类
public class Context {private Strategy strategy;//构造函数,要你使用哪个妙计public Context(Strategy strategy){this.strategy = strategy;}public void setStrategy(Strategy strategy){this.strategy = strategy;}public void operate(){this.strategy.operate();}
}
//客户类
public class Zhaoyun {public static void main(String[] args) {Context context;System.out.println("----------刚到吴国使用第一个锦囊---------------");context = new Context(new BackDoor());context.operate();System.out.println("\n");System.out.println("----------刘备乐不思蜀使用第二个锦囊---------------");context.setStrategy(new GivenGreenLight());context.operate();System.out.println("\n");System.out.println("----------孙权的追兵来了,使用第三个锦囊---------------");context.setStrategy(new BlackEnemy());context.operate();System.out.println("\n");}
}
命令模式
:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开,这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储,传递,增加,管理
角色:
- **Command类:**是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令。
- **ConcreteCommand类:**Command类的实现类,对抽象类中声明的方法进行实现。
- **Client类:**最终的客户端调用类。
以上三个类的作用应该是比较好理解的,下面我们重点说一下Invoker类和Recevier类。
- **Invoker类:**调用者,负责调用命令。
- **Receiver类:**接收者,负责接收命令并且执行命令。
案例(顾客-服务员-订单-厨师)
//Command类命令类
public interface Commend {void execute();
}
//命令实现类
public class OrderCommend implements Commend {private Order order ;private SeniorChef receiver;public OrderCommend(Order order, SeniorChef receiver) {this.order = order;this.receiver = receiver;}public void execute() {System.out.println(this.order.getDingTable()+"桌的订单");Set<String> strings = order.getMaps().keySet();for (String string : strings) {receiver.makeFood(string,order.getMaps().get(string));}System.out.println("祝您用餐愉快!");}
}//接收类
public class Order {private int dingTable;private Map<String ,Integer> maps =new HashMap<String, Integer>();public int getDingTable() {return dingTable;}public void setDingTable(int dingTable) {this.dingTable = dingTable;}public Map<String, Integer> getMaps() {return maps;}public void setMaps(String foodName,int num) {this.maps.put(foodName,num);}
}//接收类
public class SeniorChef {public void makeFood(String foodName,int num){System.out.println(foodName+" "+num+"做好了");}
}//调用者
public class waiter {private List<Commend> commends =new ArrayList<Commend>();public void addUp() {System.out.println("收到你的订单,正在通知后厨");for (Commend commend : commends) {commend.execute();}}public void setCommends(Commend commend) {this.commends.add(commend);}
}//客户类
public class Client {public static void main(String[] args) {Order order=new Order() ;order.setDingTable(123);order.setMaps("小笼包",12);Commend commend1=new OrderCommend(order,new SeniorChef());waiter waiter=new waiter() ;waiter.setCommends(commend1);waiter.addUp();}
}
jdk源码分析
:runnable 命令类
//抽象命令类
public interface Runnable {/*** When an object implementing interface <code>Runnable</code> is used* to create a thread, starting the thread causes the object's* <code>run</code> method to be called in that separately executing* thread.* <p>* The general contract of the method <code>run</code> is that it may* take any action whatsoever.** @see java.lang.Thread#run()*/public abstract void run();
}
//调用类
public
class Thread implements Runnable {/* What will be run. */ // target就是具体的命令类private Runnable target;public synchronized void start() {/*** This method is not invoked for the main method thread or "system"* group threads created/set up by the VM. Any new functionality added* to this method in the future may have to also be added to the VM.** A zero status value corresponds to state "NEW".*/if (threadStatus != 0)throw new IllegalThreadStateException();/* Notify the group that this thread is about to be started* so that it can be added to the group's list of threads* and the group's unstarted count can be decremented. */group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {/* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */}}}private native void start0();
职责链模式
:避免将一个请求的发送者和请求的处理者耦合在一起,让多个对象都有处理请求的机会。将接受请求的对象连成一条线链并且沿着这条链传递请求,直到有一个对象能够处理它为止。
角色:
Handle()、抽象处理类在类中定义了一个success的属性,抽象的处理方法。success是对下家的引用,因为不同的接受对象处理方法不同所以用抽象方法设计处理方法。通过对下个处理对象的引用行出了一条链。
ConcreteHandle(),具体的处理类,通过继承或实现抽象处理类,并且实现的对应的请求方法。当请求发送到具体的处理类时,首先进行判断是否自己能够处理该请求,如果可以则执行处理方法,否则将该请求转发给下一个具体处理类。形成一条链!
案例(员工请假-----小组长------经理-----总经理)
每个领导都有一定的权限,小组长最大1天,3,7, 如果权限不够就给上级去审批
//抽象处理类
public abstract class Handler {protected static final int ONE=1;protected static final int THREE=3;protected static final int SEVEN=7;private int numStart;private int numEnd;private Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}public Handler(int numStart, int numEnd) {this.numStart = numStart;this.numEnd = numEnd;}public abstract void handleLeave(leaveRequest leaveRequest );public void submit(leaveRequest leaveRequest ){if(this.nextHandler!=null &&leaveRequest.getDay()>this.numEnd){this.nextHandler.handleLeave(leaveRequest);}else{this.handleLeave(leaveRequest);System.out.println("流程结束!");}}}//具体的处理类
public class GourdLeader extends Handler {public GourdLeader() {super(0,Handler.ONE);}public void handleLeave(leaveRequest leaveRequest) {System.out.println(leaveRequest.getName()+"请假了"+leaveRequest.getDay()+",原因:"+leaveRequest.getReason());System.out.println("小组长审批完毕!");}
}//具体的处理类
public class GeneralManager extends Handler {public GeneralManager() {super(0, Handler.SEVEN);}public void handleLeave(leaveRequest leaveRequest) {System.out.println(leaveRequest.getName()+"请假了"+leaveRequest.getDay()+",原因:"+leaveRequest.getReason());System.out.println("总经理审批完毕!");}
}//具体的处理类
public class Manager extends Handler {public Manager() {super(0, Handler.THREE);}public void handleLeave(leaveRequest leaveRequest) {System.out.println(leaveRequest.getName()+"请假了"+leaveRequest.getDay()+",原因:"+leaveRequest.getReason());System.out.println("经理审批完毕!");}
}//请假条类
public class leaveRequest {private int day;private String name;private String reason;public leaveRequest(int day, String name, String reason) {this.day = day;this.name = name;this.reason = reason;}public int getDay() {return day;}public String getName() {return name;}public String getReason() {return reason;}public void setDay(int day) {this.day = day;}public void setName(String name) {this.name = name;}public void setReason(String reason) {this.reason = reason;}
}//客户类
public class Client {public static void main(String[] args) {leaveRequest leaveRequest =new leaveRequest(4,"张三","生病") ;Handler leader= new GourdLeader();Handler manager=new Manager();Handler generalManager=new GeneralManager();leader.setNextHandler(manager);manager.setNextHandler(generalManager);leader.submit(leaveRequest);}
}
jdk源码中的filterchain 就是使用到了职责链模式,
状态模式
:对有复杂状态的对象,把复杂的“判断逻辑” 提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变行为。
角色:
- 环境(context ) 角色:环境类中维护一个State对象,他是定义了当前的状态。
- State:抽象状态类
- ConcreteState具体状态类:每一个类封装了一个状态对应的行为
案例:
//抽象状态角色
public abstract class leftState {protected Context context;public void setContext(Context context) {this.context = context;}public abstract void start();public abstract void close();public abstract void open();public abstract void end();}//环境角色
public class Context {public static final StartState START_STATE =new StartState() ;public static final OpenState OPEN_STATE =new OpenState() ;public static final EndState END_STATE =new EndState() ;public static final CloseState CLOSE_STATE =new CloseState() ;private leftState leftState ;public leftState getLeftState() {return leftState;}public void setLeftState(leftState leftState) {this.leftState = leftState;this.leftState.setContext(this);}public void start(){this.leftState.start();}public void end(){this.leftState.end();}public void close(){this.leftState.close();}public void open(){this.leftState.open();}
}//具体状态角色
public class EndState extends leftState {@Overridepublic void start() {}@Overridepublic void close() {}@Overridepublic void open() {super.context.setLeftState(Context.OPEN_STATE);super.context.open();}@Overridepublic void end() {System.out.println("关闭。。");}
}//具体状态角色
public class CloseState extends leftState {@Overridepublic void start() {super.context.setLeftState(Context.START_STATE);super.context.start();}@Overridepublic void close() {System.out.println("关门。。。");}@Overridepublic void open() {}@Overridepublic void end() {}
}//具体状态角色
public class OpenState extends leftState{@Overridepublic void start() {}@Overridepublic void close() {}@Overridepublic void open() {System.out.println("打开。。。");}@Overridepublic void end() {super.context.setLeftState(Context.END_STATE);super.context.end();}
}//具体状态角色
public class StartState extends leftState{@Overridepublic void start() {System.out.println("开启。。。");}@Overridepublic void close() {super.context.setLeftState(Context.CLOSE_STATE);super.context.close();}@Overridepublic void open() {}@Overridepublic void end() {}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NE9laS5s-1630317263406)(C:\Users\YD\AppData\Roaming\Typora\typora-user-images\image-20210303162417249.png)]
观察者模式
:在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
角色:
抽象被观察者角色:
也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。抽象观察者角色:
为所有的具体观察者定义一个接口,在得到主题通知时更新自己。具体被观察者角色:
也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。具体观察者角色:
实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
案例:
//抽象被观察者角色
public interface Subject {void attach(Observer observer );void remove(Observer observer );void notifyChanges();
}//抽象观察者角色
public interface Observer {void update();
}//具体观察者角色
public class RealObserver implements Observer {@Overridepublic void update() {System.out.println("接收到信息!");}
}
//具体被观察者角色
public class RealSubject implements Subject {private List<Observer> observers=new ArrayList<>();@Overridepublic void attach(Observer observer) {observers.add(observer);}@Overridepublic void remove(Observer observer) {observers.remove(observer);}@Overridepublic void notifyChanges() {for (Observer observer : observers) {observer.update();}}
}
//客户类
public class Client {public static void main(String[] args) {Subject subject =new RealSubject();Observer observer =new RealObserver();subject.attach(observer);subject.notifyChanges();}
}
观察者模式,就好比微信公众号一样,被许多人关注,而公众号发生变化时,所有关注过公众号得人所关注得公众号都要发生变化。
jdk中的应用:
java中已经有一个叫Observable的类,和一个Observer的接口,实现或继承就可以用
public static class RealSubject extends Observable {public void makeChanged() {setChanged();notifyObservers();}
}public static class RealObserver implements Observer {@Overridepublic void update(Observable o, Object arg) {System.out.println("调用了-->");}
}public static void main(String[] args) {RealSubject subject = new RealSubject();RealObserver observer = new RealObserver();subject.addObserver(observer);subject.makeChanged();
}
中介模式
:定义中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。
角色:
- 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
- 具体中介者(ConcreteMediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
- 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
- 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。
//抽象中介者角色
public abstract class Mediator {public abstract void contact(String message ,Person person);
}//抽象同事角色
public abstract class Person {protected String name;protected Mediator mediator;public Person(String name, Mediator mediator) {this.name = name;this.mediator = mediator;}
}
//具体同事角色
public class Tenant extends Person {public Tenant(String name, Mediator mediator) {super(name, mediator);}public void getMessage(String message){System.out.println("租户"+name+"获取到的信息:"+message);}public void contact(String message){super.mediator.contact(message,this);}
}
//具体同事角色
public class HouseOwner extends Person {public HouseOwner(String name, Mediator mediator) {super(name, mediator);}public void getMessage(String message){System.out.println("房主"+name+"获取到的信息:"+message);}public void contact(String message){super.mediator.contact(message,this);}
}
// 具体中介者角色
public class MediatorStructure extends Mediator {private HouseOwner houseOwner ;private Tenant tenant;public HouseOwner getHouseOwner() {return houseOwner;}public void setHouseOwner(HouseOwner houseOwner) {this.houseOwner = houseOwner;}public Tenant getTenant() {return tenant;}public void setTenant(Tenant tenant) {this.tenant = tenant;}@Overridepublic void contact(String message, Person person) {if(person ==houseOwner){tenant.getMessage(message);}else{houseOwner.getMessage(message);}}
}//客户类
public class Client {public static void main(String[] args) {MediatorStructure mediator=new MediatorStructure();HouseOwner houseOwner =new HouseOwner("李四",mediator) ;Tenant tenant=new Tenant("张三",mediator);mediator.setHouseOwner(houseOwner);mediator.setTenant(tenant);houseOwner.contact("sas");tenant.contact("????");}
}
迭代器模式
:提供一个对象来顺序访问对象中的一系列数据,而不暴露聚合对象的内部表示
角色:
- 抽象迭代器角色(Iterator):此抽象角色定义出遍历元素所需的接口。
- 具体迭代器角色(ConcreteIterator):具体迭代器实现了Iterator接口,并保持迭代过程中的游标位置。
- 抽象集合角色(Collection):集合抽象角色给出创建迭代器对象的接口。
- 具体集合角色(ConcreteCollection):实现了创建迭代器对象的接口,返回一个适合的具体迭代器实例。
案例:实现list的功能
//抽象迭代器角色
public abstract class Iterator {public abstract void next();public abstract void previous();public abstract Object getPrevious();public abstract Object getNext();public abstract Boolean isNext();public abstract Boolean isFirst();
}//抽象聚合角色
public abstract class ObjectList {private List<Object> list =new ArrayList<>();public ObjectList(List<Object> list) {this.list = list;}public void add(Object o){this.list.add(o);}public void remove(Object o){this.list.remove(o);}public List<Object> getList(){return this.list;}public abstract Iterator createIterator();
}//具体迭代器角色
public class concreteIterator extends Iterator {private List<Object> list =new ArrayList<>();private int cursorFirst;private int cursorLast;public concreteIterator(ObjectList concreteObjectList ) {this.list = concreteObjectList.getList();this.cursorFirst=0;this.cursorLast=list.size()-1;}@Overridepublic void next() {if(cursorFirst<this.list.size()){cursorFirst++;}}@Overridepublic void previous() {if(cursorLast>-1){cursorLast--;}}@Overridepublic Object getPrevious() {return this.list.get(cursorLast);}@Overridepublic Object getNext() {return this.list.get(cursorFirst);}@Overridepublic Boolean isNext() {return (cursorFirst==this.list.size());}@Overridepublic Boolean isFirst() {return (cursorLast==-1);}
}//具体聚合角色
public class concreteObjectList extends ObjectList{public concreteObjectList(List<Object> list) {super(list);}@Overridepublic Iterator createIterator() {return new concreteIterator(this);}
}
//客户类
public class Client {public static void main(String[] args) {List<Object> strings =new ArrayList<>();strings.add("飒飒");strings.add("沙发上");strings.add("啊飒飒");strings.add("萨达");strings.add("阿斯顿");ObjectList objectList =new concreteObjectList(strings) ;Iterator iterator=new concreteIterator(objectList);while(!iterator.isNext()){System.out.println(iterator.getNext());iterator.next();}System.out.println("=========================");while(!iterator.isFirst()){System.out.println(iterator.getPrevious());iterator.previous();}}
}
访问者模式
:访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
分派的概念:
变量被声明时的类型叫做变量的静态类型(Static Type),有些人又把静态类型叫做明显类型(Apparent Type);而变量所引用的对象的真实类型又叫做变量的实际类型(Actual Type)
声明了一个变量list,它的静态类型(也叫明显类型)是List,而它的实际类型是ArrayList。
根据对象的类型而对方法进行的选择,就是分派(Dispatch),分派(Dispatch)又分为两种,即静态分派和动态分派。**静态分派(Static Dispatch)**发生在编译时期,分派根据静态类型信息发生。静态分派对于我们来说并不陌生,方法重载就是静态分派。**动态分派(Dynamic Dispatch)**发生在运行时期,动态分派动态地置换掉某个方法。
静态分派
Java通过方法重载支持静态分派。
public class Mozi {public void ride(Horse h){System.out.println("骑马");
}public void ride(WhiteHorse wh){System.out.println("骑白马");
}public void ride(BlackHorse bh){System.out.println("骑黑马");
}public static void main(String[] args) {Horse wh = new WhiteHorse();
Horse bh = new BlackHorse();
Mozi mozi = new Mozi();
mozi.ride(wh);
mozi.ride(bh);
}}
动态分派
Java通过方法的重写支持动态分派。
public class Horse {public void eat(){System.out.println("马吃草");
}
}
public class BlackHorse extends Horse {@Override
public void eat() {System.out.println("黑马吃草");
}
}public class Client {public static void main(String[] args) {Horse h = new BlackHorse();
h.eat();
}}
角色:
**抽象访问者(Visitor)角色:**声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口。
● **具体访问者(ConcreteVisitor)角色:**实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
● **抽象节点(Node)角色:**声明一个接受操作,接受一个访问者对象作为一个参数。
● **具体节点(ConcreteNode)角色:**实现了抽象节点所规定的接受操作。
● **结构对象(ObjectStructure)角色:**有如下的责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如List或Set。
//抽象节点角色
public interface Node {void accept(Visitor visitor);
}
//抽象访问者角色
public interface Visitor {void visit(NodeA node);void visit(NodeB node);
}//具体节点角色
public class NodeA implements Node {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public String operationA(){return "nodeA";}
}//具体节点角色
public class NodeB implements Node {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public String operationB(){return "nodeB";}
}//具体访问者角色
public class VisitorA implements Visitor{@Overridepublic void visit(NodeA node) {System.out.println(node.operationA());}@Overridepublic void visit(NodeB node) {System.out.println(node.operationB());}
}//具体访问者角色
public class VisitorB implements Visitor {@Overridepublic void visit(NodeA node) {System.out.println(node.operationA());}@Overridepublic void visit(NodeB node) {System.out.println(node.operationB());}
}
//结构对象角色
public class ObjectStructure {private List<Node> nodes =new ArrayList<>();public void action(Visitor visitor){for (Node node : nodes) {node.accept(visitor);}}public void add(Node node){nodes.add(node);}
}
//客户类
public class Client {public static void main(String[] args) {ObjectStructure os =new ObjectStructure() ;os.add(new NodeA());os.add(new NodeB());Visitor visitor=new VisitorB();os.action(visitor);}
}
备忘录模式
:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
角色:
- Originator: 原发器,决定Memento存储Originator的哪些内部状态。保存状态时负责创建一个备忘录,还原的时候利用一个备忘录进行恢复。
- Memento: 备忘录,用于存储Originator的内部状态,也就是要被恢复的对象的状态,并且可以防止Originator以外的对象非法访问Memento。
- Caretaker: 负责人,负责保存好备忘录,不能对备忘录的内容进行操作和访问,只能够将备忘录传递给其他对象。当备忘录份数过多时,根据需要使用相关容器进行组织(list、stack),当程序结束的时候,根据需要是否要先进行序列化和持久化。
//原发器(实际操作的对象)
public class Originator {private String name;private String major;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getMajor() {return major;}public void setMajor(String major) {this.major = major;}public Originator(String name, String major) {this.name = name;this.major = major;}public void ReCoverMemento(Memento memento){this.major=memento.getMajor();this.name=memento.getName();}public Memento memoOperation(){return new Memento(this);}
}//备忘录角色(保存操作后原发器的数据)
public class Memento {private String name;private String major;public Memento(Originator originator) {this.name = originator.getName();this.major=originator.getMajor();}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getMajor() {return major;}public void setMajor(String major) {this.major = major;}
}//负责人角色(实现撤销,还原原发器之前的状态)
public class CareMaker {private Stack<Memento> mementos =new Stack<>();public Memento getMementos() {if(!mementos.isEmpty()){return mementos.pop();}return null;}public void setMementos(Memento memento) {mementos.push(memento);}
}
//客户类,测试
public class Client {public static void main(String[] args) {Originator originator=new Originator("lisi","computer");Memento memento = originator.memoOperation();CareMaker careMaker =new CareMaker();careMaker.setMementos(memento);System.out.println("本专业:"+originator.getMajor());originator.setMajor("物流");System.out.println("换专业后:"+originator.getMajor());careMaker.setMementos(originator.memoOperation());System.out.println("发现这个专业比上个专业还差,撤销!");careMaker.getMementos();Memento mementos = careMaker.getMementos();originator.ReCoverMemento(mementos);System.out.println("现在的专业:"+originator.getMajor());}
}
解释器模式
:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
角色:
- 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
- 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
实例:计算(a*b)/(a-b+2)
//环境角色
public class Context {private Map<String,Integer> values=new HashMap<>();public void addValue(String key,int value){values.put(key,value);}public int getValue(String key){return values.get(key);}
}//抽象表达式角色
public abstract class AbstractExpression {public abstract int interpreter(Context context);}//非终结符表达式角色
public class TerminalExpression extends AbstractExpression {private final String name;public TerminalExpression(String name) {this.name = name;}@Overridepublic int interpreter(Context context) {return context.getValue(name);}
}//终结符表达式角色
public class DivisionExpression extends AbstractExpression{private AbstractExpression left;private AbstractExpression right;public DivisionExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpreter(Context context) {int value=this.right.interpreter(context);if(value!=0){return this.left.interpreter(context)/value;}return -11111;}
}//终结符表达式角色
public class MultiplyExpression extends AbstractExpression{private AbstractExpression left;private AbstractExpression right;public MultiplyExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpreter(Context context) {return this.left.interpreter(context)*this.right.interpreter(context);}
}//终结符表达式角色
public class SubtractExpression extends AbstractExpression {private AbstractExpression left;private AbstractExpression right;public SubtractExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpreter(Context context) {return this.left.interpreter(context)-this.right.interpreter(context);}
}
//终结符表达式角色
public class AddExpression extends AbstractExpression {private AbstractExpression left;private AbstractExpression right;public AddExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpreter(Context context) {return this.left.interpreter(context)+this.right.interpreter(context);}
}
//客户端调用
public class Client {public static void main(String[] args) {Context context =new Context() ;context.addValue("a",11);context.addValue("b",12);AbstractExpression addExpression =new AddExpression(new TerminalExpression("a"),new TerminalExpression("b"));System.out.println(addExpression.interpreter(context));}
}
xpression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
实例:计算(a*b)/(a-b+2)
//环境角色
public class Context {private Map<String,Integer> values=new HashMap<>();public void addValue(String key,int value){values.put(key,value);}public int getValue(String key){return values.get(key);}
}//抽象表达式角色
public abstract class AbstractExpression {public abstract int interpreter(Context context);}//非终结符表达式角色
public class TerminalExpression extends AbstractExpression {private final String name;public TerminalExpression(String name) {this.name = name;}@Overridepublic int interpreter(Context context) {return context.getValue(name);}
}//终结符表达式角色
public class DivisionExpression extends AbstractExpression{private AbstractExpression left;private AbstractExpression right;public DivisionExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpreter(Context context) {int value=this.right.interpreter(context);if(value!=0){return this.left.interpreter(context)/value;}return -11111;}
}//终结符表达式角色
public class MultiplyExpression extends AbstractExpression{private AbstractExpression left;private AbstractExpression right;public MultiplyExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpreter(Context context) {return this.left.interpreter(context)*this.right.interpreter(context);}
}//终结符表达式角色
public class SubtractExpression extends AbstractExpression {private AbstractExpression left;private AbstractExpression right;public SubtractExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpreter(Context context) {return this.left.interpreter(context)-this.right.interpreter(context);}
}
//终结符表达式角色
public class AddExpression extends AbstractExpression {private AbstractExpression left;private AbstractExpression right;public AddExpression(AbstractExpression left, AbstractExpression right) {this.left = left;this.right = right;}@Overridepublic int interpreter(Context context) {return this.left.interpreter(context)+this.right.interpreter(context);}
}
//客户端调用
public class Client {public static void main(String[] args) {Context context =new Context() ;context.addValue("a",11);context.addValue("b",12);AbstractExpression addExpression =new AddExpression(new TerminalExpression("a"),new TerminalExpression("b"));System.out.println(addExpression.interpreter(context));}
}
参考于黑马程序员的java设计模式教程
https://www.bilibili.com/video/BV1tK411u7uQ
java设计模式案例及使用相关推荐
- Java设计模式-七大设计原则
Java设计模式 设计模式七大原则 设计模式的目的 编写软件过程中,程序员面临着来自 耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性 等多方面的挑战,设计模式是为了让程序(软件),具有更好 代码 ...
- Java设计模式之行为型:状态模式
背景: 介绍状态模式前,我们先看这样一个实例:公司力排万难终于获得某个酒店的系统开发项目,并且最终落到了你的头上.下图是他们系统的主要工作: 当第一眼看到这个系统时你就看出这是一个状态图,每个框都代表 ...
- 烂代码解决方案:Java设计模式的魅力
设计模式本身是一种通用场景的解决标准和方案,而不是实际场景开发落地的指导手册.这种通用的解决标准和方案是研发人员在大量的项目中验证和提炼的结果,如果只是学习理论知识,没有经历过大型的项目开发,则很难理 ...
- 我以订披萨为例,给朋友详细讲了Java设计模式的3种工厂模式
摘要:工厂模式是将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦.从而提高项目的扩展和维护性. 本文分享自华为云社区<[Java设计模式]用 披萨订购案例 详 ...
- java设计模式 建造模式_理解java设计模式之建造者模式
理解java设计模式之建造者模式 发布于 2020-12-10| 复制链接 摘记: 建造者模式(Builder Pattern)主要用于"分步骤构建一个复杂的对象",在这其中&qu ...
- 里氏替换原则——举例说明Java设计模式中的里氏替换原则
里氏替换原则--举例说明Java设计模式中的里氏替换原则 1. 前言 官方定义: 2. 举例说明 2.1 例子介绍 2.2 反例 2.2.1 类图说明 2.2.2 代码说明 2.2.3 测试 2.2. ...
- 【Java设计模式】组合模式
转自: https://blog.csdn.net/qq_42322103/article/details/95457321 漫谈网站优化提速: https://blog.csdn.net/mete ...
- Java设计模式大全
文章目录 1. Java设计模式大体上分为三大类介绍 2. 设计模式遵循的六大原则 3. Java的23种设计模式: 3.1 创建型模式 3.1.1. 工厂模式(Factory Method) 3.1 ...
- Java设计模式之模板方法模式(UML类图分析+代码详解)
大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...
- java设计模式:23种设计模式及其源代码演示实现
java23种设计模式及其源代码演示实现 博主在CSDN已有三年,之前一直在看贴,受益颇多,不可多得的一个良好的学习平台,这一次,博主给大家分享一份传说中的java设计模式,源代码与其实现全部都有,希 ...
最新文章
- python连接linux服务器并使用命令_python基于paramiko模块实现远程连接Linux虚拟机(服务器)并执行指定命令返回输出结果...
- ASIHTTPRequest的环境配置和使用示例
- 进制转换c++代码_跟小黑学漏洞利用开发之16进制字符转换
- 处理字符串_8_判断字符串含有汉字
- zigbee 串口不稳定_Zigbee
- Django-你想知道的都在这里
- Oracle的to_char()函数使用
- el alert 点击添加时提示_JavaScript 有三种类型:警告框、确认框和提示框使用详解...
- [补档]noip2019集训测试赛(九)
- LeetCode-179:数组自动排序工具Arrays.sort(),比较器Comparator的正确打开方式
- Windows系统服务器IIS7.5 Asp.net支持10万请求的设置方法
- 关于c语言打印图案的解析,c语言星号打印矩形、三角形、菱形等图案和答案解析.doc...
- 区块链和央行数字货币DCEP
- Spring整合mybatis事务管理
- idea实现打包springboot项目并且运行在cmd中
- 查询2021高考成绩位次,2021年江苏高考位次表及高考个人成绩排名查询
- macos 微信小助手
- u盘打不开,提示需要格式化怎么办?
- 光伏并网逆变器设计方案,附有相关的matlab电路仿真文件,以及DSP的程序代码
- 【Excel】如何使用RegexString正则表达式
热门文章
- mysql数据库学习(基础篇)
- mySQL数据库学习的一些心得
- A7芯片 IOS降级 跳过ID | ipad Mini2降级 10.3.3
- 华为HCIE云计算之FC添加ipsan数据存储
- python手写输入法开发_QT 手写输入法 - 程序员狗蛋的个人空间 - OSCHINA - 中文开源技术交流社区...
- 基于Springboot的物业管理系统_代码
- netty权威指南-第三章——netty入门应用
- vbs字符串正则_VBS教程:正则表达式简介 -字符匹配
- 《数学之友》期刊简介及投稿要求
- 如何查看python标准库_python标准库