Java实现23种设计模式教程(3)

网友投稿 586 2022-05-30

要实现如上的结果,我们这次不用静态代理,而是用JDK动态代理

其实所谓的动态代理,也就是不用写代理类了,而是又JDK底层通过反射在内存中帮你创建好了一个代理类

public class logger implements loggers { /** * JDK动态代理: * 我们无需创建代理类,而是有JDK底层的反射帮我们在内存中自动创建 */ @Override public void writerlogger() { System.out.println("写入日志。。"); } }

public interface loggers { void writerlogger(); }

动态代理:

public class loggerProxyMain { private static logger logger=new logger(); public static void main(String[] args) { /** * public static Object newProxyInstance(ClassLoader loader, * Class[] interfaces, * InvocationHandler h) */ loggers loggers= (com.design.proxy.dongtaiProxy.loggers) Proxy.newProxyInstance(logger.class.getClassLoader(), logger.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /* 第一个参数:被代理的类的对象 第二个参数:方法参数args */ System.out.println("代理开始===="); //如果用代理实例调用方法,将会在这里执行 Object invoke = method.invoke(logger, args);//不返回这个对象的话,代理实例为null System.out.println("代理结束"); return invoke; //返回代理实例,并返回到loggers对象中 } }); //****注意:进入invoke方法是有前提的,就是我们要使用代理实例对象loggers,如果不使用它就不会进入到invoke方法中 //输入logger对象也行,也可以让他进入invoke方法 // System.out.println(loggers); /* 当我们去调用代理的方法时,method.invoke就会监听到,并执行被代理的方法 */ loggers.writerlogger(); } }

装饰器模式

我们可以把装饰器分为主菜和配菜,配菜就是装饰器,而主菜就是被装饰的

公式:创建一个抽象类(作为被装饰者的父类),被装饰者类去继承它,然后创建装饰者抽象类并继承被装饰者的父类,再有装饰者子类去继承装饰者抽象类。

案例:

被装饰者的抽象类,在这里是最高的类

public abstract class breakFast { public abstract int cost(); //价格 }

被装饰者具体类

public class rice extends breakFast { /** * 主食:米饭 */ @Override public int cost() { return 5; } }

public class noodles extends breakFast { /** *主食: 面条 */ @Override public int cost() { return 10; } }

装饰者抽象类:继承与被装饰者的父类

public abstract class decorations extends breakFast{ public abstract int cost(); //装饰者的钱 }

装饰者类

public class coke extends decorations { private breakFast breakFast; private final int COKE_COST=2; //coke的价格 public coke(breakFast breakFast){ this.breakFast=breakFast; } @Override public int cost() { return breakFast.cost()+COKE_COST; } }

public class milk extends decorations { private breakFast breakFast; private final int MILK_COST=3; //milk的价格 public milk(breakFast breakFast){ this.breakFast=breakFast; } @Override public int cost() { return breakFast.cost()+MILK_COST; } }

Java实现23种设计模式教程(3)

测试:

public class main { public static void main(String[] args) { rice rice = new rice(); //创建被装饰者对象 milk milk = new milk(rice);//把被装饰者对象放到装饰者的构造方法上去 System.out.println("rice:"+rice.cost()); System.out.println("milk+rice:"+milk.cost()); milk milk1 = new milk(milk); System.out.println("milk*2+rice"+milk1.cost()); } }

适配器模式

适配器模式:就是把原本互不兼容的两样东西或者格式,转换成可以兼容

比如说:家用电压是220v,但是我们手机充电不需要这么大的电压,我们这时候需要电源适配器(充电头),去适配这个电压,把220v适配成(比如:5v,11v等等)

再比如说:有一个方法只能接收int类型数据,但是我们接收到了一个String类型数据,int和String本身就是两个不相同的类型,所以说这个方法是接收不到String类型的,我们可以使用适配器,把String类型转换(适配)成int类型,这样这个方法就可以接收到这个String类型数据了。

公式:适配器类要继承src(原来的类),并实现dest(目标)接口

首先创建适配器类,并运用上面的公式:

public class classAdapter extends srcClass implements destInterface{ /** * 类适配器是有公式的 * 公式:类适配器要继承源类,实现于目标接口 * public class classAdapter extends srcClass implements destInterface * * srcClass:在这里是指家用电压220V * destInterface : 在这里是指我们想适配成多少v的电压,比如手机常用的电压 5v */ @Override public int vivoBattery_5V() { int src = super.getSrc(); int dest=src/44; return dest; } }

源(src)类:

public class srcClass { private final int v=220; //家用电压 //源类生成220v public int getSrc(){ return v; } }

目标接口:

public interface destInterface { int vivoBattery_5V(); //vivo手机想要多少伏的电压 }

测试:

public class Test { public static void main(String[] args) { classAdapter classAdapter = new classAdapter(); int res = classAdapter.vivoBattery_5V(); System.out.println("当前电压:"+res+"v"); } }

为什么会有对象适配器:我们的对象适配器都是在类适配器上优化的,类适配器的缺点是extends(继承),因为Java是单继承的,而我们的对象适配器不过就是把这个extends srcClass 优化成一个对象,通过构造器进行传入,然后通过这个对象进行调用srcClass的方法,而类适配器就是通过super关键字去调用方法。。

public class adapter implements destInterface { private srcClass srcClass; //把之前的类适配器的extends 源类,改成一个对象进行调用 public adapter(srcClass srcClass){ //再通过构造器传入srcClass对象 this.srcClass=srcClass; } @Override public int get10V() { int src = srcClass.getV(); int dest=src/22; return dest; } }

public interface destInterface { int get10V(); }

public class srcClass { private final int v=220; public int getV(){ return v; } }

public class Test { public static void main(String[] args) { adapter adapter = new adapter(new srcClass()); int v = adapter.get10V(); System.out.println(v); } }

为何有接口适配器:我们上面说的两种适配器方式都有一个缺点:就是我们上面两种适配器都需要实现目标接口,当目标接口有多个适配方法时,我们都要对它进行实现,而我们不需要全部实现,只需要实现其中一个即可,我们的接口适配器就是为了解决这个问题的。

没有给接口方法默认实现时:

public interface dest { int adapter_5v(); int adapter_10v(); int adapter_20v(); }

public class adapter implements dest { @Override public int adapter_5v() { return 0; } @Override public int adapter_10v() { return 0; } @Override public int adapter_20v() { return 0; } }

就需要全部进行实现,很复杂

public class srcClass { private final int v=220; //家用电压 //源类生成220v public int getSrc(){ return v; } }

public interface dest { /** * 当接口适配的方法很多,但是我们不需要全部的进行实现,我们可以随便给他一个默认值,用default修饰 * 当我们需要具体实现某个方法时,只需要重写对应的方法即可 */ default int adapter_5v(){ return 0; } default int adapter_10v(){ return 0; } default int adapter_20v(){ return 0; } }

public class adapter implements dest { private srcClass srcClass; public adapter(srcClass srcClass){ this.srcClass=srcClass; } @Override public int adapter_10v() { int src = srcClass.getSrc(); int res=src/22; return res; } }

class main{ public static void main(String[] args) { adapter adapter = new adapter(new srcClass()); int i = adapter.adapter_10v(); System.out.println(i); } }

享元模式

享元模式:“享”是共享 ,“元”是对象 ,享元模式也就是一种利用共享技术对实例对象进行共享,提高实例对象的复用性,和节省资源的开销,减少对象的创建,应用在大量的“”相似“”对象,但是这些对象只有一些不同,我们可以用这个模式。

享元模式如何在定制相似的对象(对对象的数据进行修改):我们可以通过享元模式的简单工厂从HashMap/HashTable中get到,然后再用set方法对它进行定制。

何为相似的对象: 说白了也就是同一个类创建出来的对象就是相似的对象

案例:用户的网站界面属性(网站类型(type)、颜色(color),动态消息(message))

public abstract class website { /** * 总的网站抽象类 */ public abstract void setColor(String color); public abstract void setMessages(List messages); public abstract void setRandomCode(String randomCode); }

public class sina extends website { /** * 新浪网站 */ private final String type="新浪"; private String color; private List messages; private String randomCode; //随机码 public sina() { } public String getType() { return type; } public String getColor() { return color; } public List getMessages() { return messages; } public String getRandomCode() { return randomCode; } @Override public String toString() { return "sina{" + "type='" + type + '\'' + ", color='" + color + '\'' + ", messages=" + messages + ", randomCode='" + randomCode + '\'' + '}'; } @Override public void setColor(String color) { this.color=color; } @Override public void setMessages(List messages) { this.messages=messages; } @Override public void setRandomCode(String randomCode) { this.randomCode=randomCode; } }

public class zhihu extends website { /** * 知乎 */ private final String type="知乎"; private String color; private List messages; private String randomCode; public zhihu() { } public String getType() { return type; } public String getColor() { return color; } public List getMessages() { return messages; } public String getRandomCode() { return randomCode; } @Override public String toString() { return "zhihu{" + "type='" + type + '\'' + ", color='" + color + '\'' + ", messages=" + messages + ", randomCode='" + randomCode + '\'' + '}'; } @Override public void setColor(String color) { this.color=color; } @Override public void setMessages(List messages) { this.messages=messages; } @Override public void setRandomCode(String randomCode) { this.randomCode=randomCode; } }

享元工厂(相当于简单工厂的升级版):

这边存在线程安全问题,因为getWebsiteByFactory方法不是原子操作,所以我们多线程环境下一定要加锁

public class simpleFactory { /** * 享元模式是需要简单工厂模式的 */ private Map map=new HashMap<>(); //享元模式精髓 private String[] colors={"red","blue","yellow","green","orange"}; public website getWebsiteByFactory(String type){ if(type==null||type.equals("")) { return null; }else { website website = map.get(type); if(website==null){ //用简单工厂模式来书写 if(type.equals("新浪")){ sina sina = new sina(); Random random = new Random(); int index = random.nextInt(5); sina.setColor(colors[index]); int i = random.nextInt(1000); ArrayList list = new ArrayList<>(); list.add("hello"+i); sina.setMessages(list); sina.setRandomCode(String.valueOf(random.nextInt(9999))); map.put(type,sina); System.out.println("创建新浪网站对象成功"); return sina; }else if(type.equals("知乎")){ zhihu zhihu = new zhihu(); Random random = new Random(); zhihu.setColor(colors[random.nextInt(5)]); ArrayList list = new ArrayList<>(); list.add("hello"+random.nextInt(1000)); zhihu.setMessages(list); zhihu.setRandomCode(String.valueOf(random.nextInt(9999))); map.put(type,zhihu); System.out.println("创建知乎网站成功"); return zhihu; }else { return null; } }else { System.out.println("在享元模式的简单工厂中已经存在这个网站,所以直接获取到,没有重新创建对象"); return website; } } } }

测试:

public class main { private static final String[] websites={"新浪","知乎"}; public static void main(String[] args) { simpleFactory simpleFactory = new simpleFactory(); //创建享元模式的简单工厂 website s1 = simpleFactory.getWebsiteByFactory("新浪"); System.out.println(s1); //会创建对象 /** * 享元模式重要作用之一:定制对象 */ s1.setColor("利用享元模式定制对象"); website s2 = simpleFactory.getWebsiteByFactory("新浪"); System.out.println(s2); //不会创建对象,而是从map里面拿 Random random = new Random(); // for (int i = 0; i < 20; i++) { // new Thread(()->{ // website website = simpleFactory.getWebsiteByFactory(websites[random.nextInt(2)]); // System.out.println(website); // // }).start(); // } } }

输出结果:

创建新浪网站对象成功 sina{type='新浪', color='red', messages=[hello713], randomCode='2522'} 在享元模式的简单工厂中已经存在这个网站,所以直接获取到,没有重新创建对象 sina{type='新浪', color='利用享元模式定制对象', messages=[hello713], randomCode='2522'}

只需在getWebsiteByFactory方法上加锁即可

public class simpleFactory { /** * 享元模式是需要简单工厂模式的 */ private Map map=new HashMap<>(); //享元模式精髓 private String[] colors={"red","blue","yellow","green","orange"}; public synchronized website getWebsiteByFactory(String type){

组合模式(树型结构)

组合模式的项目应用:实现多级菜单 、文件夹的管理

组合模式我们把它看成一种“树”型结构,固然后面我们在打印这些内容的时候是需要用递归的

因为组合模式是按照树形结构来组合的,所以也有树的特点(比如:叶子节点)

案例:利用组合模式来实现三级菜单。

定义组合模式的菜单组件接口,并定义添加、删除、展示结点方法:

public interface component { /** * 组件接口:所有菜单都要实现这个component(组件)接口 * 组合模式所需方法:添加结点、删除结点、打印菜单 */ //需要给这个添加结点一个默认实现,因为我们的叶子结点不需要添加结点和删除结点这两个方法 default void addNode(component component){ throw new UnsupportedOperationException();//默认抛出不支持操作异常 } default void deleteNode(component component){ throw new UnsupportedOperationException(); } //打印===都需要实现 void showMenu(); }

菜单组件实现类(非叶子结点==第一、二级菜单):

一级菜单:

public class firstMenu implements component { /** * 一级菜单 */ private String name; //菜单名称 private List components; public firstMenu(String name){ this.name=name; this.components=new ArrayList<>(); } @Override public void addNode(component component) { components.add(component); } @Override public void deleteNode(component component) { components.remove(component); } @Override public void showMenu() { System.out.println("---"+this.getName()); //打印当前调用者的名称 if(components.size()>0){ for (component component : components) { component.showMenu(); //递归的调用这个showMenu方法 } } } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getComponents() { return components; } public void setComponents(List components) { this.components = components; } }

二级菜单:

public class secondMenu implements component { /** * 二级菜单 */ private String name; private List components; public secondMenu(String name){ this.name=name; this.components=new ArrayList<>(); } @Override public void addNode(component component) { components.add(component); } @Override public void deleteNode(component component) { components.remove(component); } @Override public void showMenu() { System.out.println("------"+this.getName()); if(components.size()>0){ for (component component : components) { component.showMenu();; } } } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getComponents() { return components; } public void setComponents(List components) { this.components = components; } }

三级菜单:(叶子节点),没有添加、删除结点方法

public class lastMenu implements component { private String name; /** * 最后一个菜单(三级菜单):不能添加和删除,因为它是树的叶子结点 */ public lastMenu(String name){ this.name=name; } @Override public void showMenu() { System.out.println("---------"+this.name); } }

组合模式客户端代码:

public class client { /** * 组合模式客户端 * @param args */ public static void main(String[] args) { //创建一级菜单 component f1=new firstMenu("用户列表"); //创建二级菜单 component s1=new secondMenu("用户信息"); component s2=new secondMenu("用户权限"); component s3=new secondMenu("用户好友"); //创建三级菜单 component l1=new lastMenu("信息修改"); component l2=new lastMenu("信息删除"); component l3=new lastMenu("修改权限"); component l4=new lastMenu("添加好友"); component l5=new lastMenu("删除好友"); component l6=new lastMenu("修改好友信息"); //进行组合 f1.addNode(s1); f1.addNode(s2); f1.addNode(s3); s1.addNode(l1); s1.addNode(l2); s2.addNode(l3); s3.addNode(l4); s3.addNode(l5); s3.addNode(l6); //展示菜单 f1.showMenu(); } }

输出结果:

---用户列表 ------用户信息 ---------信息修改 ---------信息删除 ------用户权限 ---------修改权限 ------用户好友 ---------添加好友 ---------删除好友 ---------修改好友信息

外观模式

为什么会有外观模式?外观模式能解决什么?其实就是把其他对象调用方法封装到外观类上,我们只需要通过调用外观类的方法就可以调用其他类的方法

总结:外观模式(门面模式)说白了就是把多个不同对象(类)的方法归纳到一个门面类(外观类)中,这样省去频繁创建对象,核心就是门面类

使用两种方法实现案例“买水果问题”。。

苹果实体类:

public class apple { /** * 苹果实体类 */ private String id; private String name; public apple(String name){ this.name=name; } public void setId(String id) { this.id = id; } public String getName() { return name; } @Override public String toString() { return "apple{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } }

public class banana { /** * 香蕉实体类 */ private String id; private String name; public banana(String name){ this.name=name; } public void setId(String id) { this.id = id; } public String getName() { return name; } @Override public String toString() { return "banana{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } }

public class orange { /** * 橙子实体类 */ private String id; private String name; public orange(String name){ this.name=name; } public void setId(String id) { this.id = id; } public String getName() { return name; } @Override public String toString() { return "orange{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } }

创建各自的商店:

public class appleStore { /** * 苹果专卖店 */ //买苹果 public apple buyApple(){ apple apple = new apple("苹果"); apple.setId(UUID.randomUUID().toString().replaceAll("-","")); return apple; } }

public class bananaStore { //香蕉实体店 public banana buyBanana(){ banana banana = new banana("香蕉"); banana.setId(UUID.randomUUID().toString().replaceAll("-","")); return banana; } }

public class orangeStore { //橙子实体店 public orange buyOrange(){ orange orange=new orange("橙子"); orange.setId(UUID.randomUUID().toString().replaceAll("-","")); return orange; } }

顾客买水果:

public class client { public static void main(String[] args) { //买苹果 //1.创建苹果店对象 appleStore appleStore = new appleStore(); //2.购买 apple apple = appleStore.buyApple(); //买香蕉 bananaStore bananaStore = new bananaStore(); banana banana = bananaStore.buyBanana(); //买橙子 orangeStore orangeStore = new orangeStore(); orange orange = orangeStore.buyOrange(); System.out.println(apple); System.out.println(banana); System.out.println(orange); } }

====================

总结:可以看出来使用传统方法买水果比较复杂,顾客需要创建各自的商店,再去购买。。。

上面实体类不变,只需要添加一个门面类(外观类)即可

核心(外观类):

public class myFacade { /** * 创建门面类(外观类) */ //这几个变量也可以写成单例,这里暂且不写 private appleStore appleStore; private bananaStore bananaStore; private orangeStore orangeStore; public myFacade(){ //初始化对象 this.appleStore=new appleStore(); this.bananaStore=new bananaStore(); this.orangeStore=new orangeStore(); } /** * 精髓。。。 * 使用外观模式的外观类来归纳方法,把多个类的方法归纳到一个外观类中 * @return */ //创建门面方法(外观方法),购买水果 //买苹果 public apple buyAppleByfacade(){ apple apple = appleStore.buyApple(); apple.setId(UUID.randomUUID().toString().replaceAll("-","")); return apple; } //买香蕉 public banana buyBananaByfacade(){ banana banana = bananaStore.buyBanana(); banana.setId(UUID.randomUUID().toString().replaceAll("-","")); return banana; } //买橙子 public orange buyOrangeByfacade(){ orange orange = orangeStore.buyOrange(); orange.setId(UUID.randomUUID().toString().replaceAll("-","")); return orange; } }

public class client { public static void main(String[] args) { //创建已经归纳好方法的外观类 myFacade myFacade = new myFacade(); //购买水果 apple apple = myFacade.buyAppleByfacade(); banana banana = myFacade.buyBananaByfacade(); orange orange = myFacade.buyOrangeByfacade(); System.out.println(apple); System.out.println(banana); System.out.println(orange); } }

这时候我们不需要创建商店了,只需要创建外观类调用买水果方法即可。

外观模式优点:假如水果有1000种,那么我们就要创建1000个对象,而使用外观模式,只需要创建一个外观类的对象即可,只需要1个对象。这样对比起来就相当明显了。。。。。。。。。。。。。。。。。。

桥接模式

使用桥接类和需要被桥接的接口进行桥接

案例:假设我们需要一个接口,用来连接mysql或者Oracle

public interface connection { public void connectDatasource(); }

public class connection_mysql implements connection { /* 连接mysql数据源 */ @Override public void connectDatasource() { System.out.println("mysql数据源连接成功!!!"); } }

public class connection_oracle implements connection { /* 连接Oracle数据源 */ @Override public void connectDatasource() { System.out.println("oracle数据源连接成功!!!"); } }

传统方式测试:

public class client_chuantong { public static void main(String[] args) { //传统方法调用接口方法 connection connection=new connection_mysql(); connection.connectDatasource(); connection connection1=new connection_oracle(); connection.connectDatasource(); } }

桥的抽象类:

public abstract class bridge { /** * 桥的抽象类 */ public abstract void connection(); }

桥的实现类

public class bridgeImpl extends bridge { /** * 核心 * 使用了桥接模式之后,我们只需要创建桥接 */ private connection connection; //给对象注入 public bridgeImpl(connection connection){ this.connection=connection; } //桥接方法(桥接接口方法) @Override public void connection() { connection.connectDatasource(); } }

桥接测试:

public class client_bridge { public static void main(String[] args) { //使用桥接实现类调用被桥接的接口方法 bridge bridge = new bridgeImpl(new connection_oracle()); bridge.connection(); } }

观察者模式

既然有观察者,那么也就有被观察者。一个被观察者被多个观察者观察。比如说天气预报,天气预报就是被观察者,订阅了天气预报的人就是观察者,天气预报需要通知观察者。

被观察者接口:

public interface observerable { /** * 被观察者 */ //添加观察者 public void addObserver(observer observer); //移除观察者 public void removeObserver(observer observer); //通知所有观察者 public void notifyAllObserver(); }

观察者接口:

public interface observer { /** * 观察者 */ //接收通知的方法 public void getTianqi(tianqi tianqi); }

被观察者(在这是天气预报):

public class tianqi implements observerable { /** * 被观察者 :天气预报 */ private String date;//日期 private String wendu;//摄氏度 private List observers; //管理所有观察者,以便通知观察者们(其实也就是调用观察者的接收通知方法) public tianqi(){ this.observers=new ArrayList<>(); this.date="2021/5/9"; this.wendu="37°C"; } public tianqi(String date, String wendu) { this.date=date; this.wendu=wendu; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getWendu() { return wendu; } public void setWendu(String wendu) { this.wendu = wendu; } @Override public void addObserver(observer observer) { observers.add(observer); } @Override public void removeObserver(observer observer) { observers.remove(observer); } @Override public void notifyAllObserver() { if(observers.size()>0){ for (int i = 0; i < observers.size(); i++) { observers.get(i).getTianqi(new tianqi(this.date,this.wendu)); } }else{ System.out.println("没有人订阅过天气预报。。。"); } } @Override public String toString() { return "天气信息{" + "date='" + date + '\'' + ", wendu='" + wendu + '\'' + '}'; } }

观察者:

public class person implements observer { /** * 人:观察者 */ private String name; //观察者名字 public person(String name){ this.name=name; } @Override public void getTianqi(tianqi tianqi) { System.out.println("当前用户名为:"+name+","+tianqi); } }

客户端(测试):

public class client { public static void main(String[] args) { tianqi tianqi = new tianqi(); tianqi.addObserver(new person("小明")); tianqi.addObserver(new person("小华")); tianqi.notifyAllObserver(); System.out.println("=======修改后"); tianqi.addObserver(new person("小刘")); tianqi.setDate("2021/5/10"); tianqi.setWendu("15°C"); tianqi.notifyAllObserver(); } }

备忘录模式

备忘录模式:可以用来备份数据和恢复

备忘录需要有三个类:需要备份的类、originator(生成需要备份的类的对象),存储数据和恢复数据的类

责任链模式

策略模式

模板模式

Java 网站

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:智联世界—车联网的应用和数字化未来发展(排放检测篇)
下一篇:2018,全新出发(全力推动实现住有所居)
相关文章