适配器模式
工作场景:
经常用来做旧系统的改造和升级
由于应用环境变化,需要将一些“现存的对象”放在新的环境中应用,但是新的环境要求的接口是这些现存对象所不满足的。
如果我们的系统开发之后再也不需要维护,那么很多模式都是没必要的,但不幸的是,事实却是维护一个系统的代价往往是开发一个系统的数倍
目的:
将一个类的接口转换为客户希望的另一个接口。Adapter模式是的原本由于接口不兼容而不能一起工作的那些类可以一起工作。
假设有这样一个场景,我们有一个手机需要充电,我们有充电器,但是身边只有一个三孔的插座,此时呢,我们呢需要有一个适配器,来插到这个三孔插座,我们的充电器再插到这个适配器上完成充电功能,
此时呢,手机只需要于适配器对接,而不需要访问原来的三孔插座,因为适配器已经和三孔插座适配了。
适配器有对象适配器和类适配器两种
UML:
对象适配器
类适配器
代码:
public interface Target { void shipei(); } //对象适配器 public class Adapter implements Target{ private Charger charger; @Override public void shipei() { // TODO Auto-generated method stub charger.chongdian(); } public Adapter(Charger charger) { super(); this.charger = charger; } } //类适配器 public class Adapter2 extends Charger implements Target{ @Override public void shipei() { // TODO Auto-generated method stub super.chongdian(); } } public class Charger { //完成手机充电功能 public void chongdian() { System.out.println("手机正在充电。。。。。"); } } public class UserEntry { public void objectAdapter() { Client client=new Client(); Charger charger=new Charger(); Target adapter=new Adapter(charger); client.test(adapter); } public void classAdapter() { Client client=new Client(); Charger charger=new Charger(); Target adapter=new Adapter2(); client.test(adapter); } } //插座, public class Client { public void test(Target t) { t.shipei(); } public static void main(String[] args) { //对象适配器调用 new UserEntry().objectAdapter(); System.out.println("---------"); //类适配器调用 new UserEntry().classAdapter(); } }
结果:
手机正在充电。。。。。
手机正在充电。。。。。
两者区别:
类适配器采用“多继承”的实现方式,带来 了不良的高耦合,所以一般不推荐使用。对象适配器采用 “对象组合”的方式,更符合松耦合精神。
桥接模式
核心:
处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,是各个维度可以独立的扩展在抽象层建立关联.
优点:
桥接模式极大提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有的系统,符合开闭原则。
当一个类有多维度变化时,用桥接模式可以极大降低程序的复杂度,将抽象部分与实现部分分离,使他们都可以独立的变化
UML:
代码:
public interface Brand { void sale(); } public class Asus implements Brand{ @Override public void sale() { System.out.println("asus产品"); } } public class Dell implements Brand { @Override public void sale() { System.out.println("dell品牌"); } } public class Lenovo implements Brand{ @Override public void sale() { System.out.println("lenovo产品"); } } public class Computer { private Brand brand; public Computer(Brand brand) { super(); this.brand = brand; } public void sale() { brand.sale(); } } class Disktop extends Computer{ public Disktop(Brand brand) { super(brand); } public void sale() { super.sale(); System.out.println("台式机电脑"); } } class Laptop extends Computer{ public Laptop(Brand brand) { super(brand); // TODO Auto-generated constructor stub } public void sale() { super.sale(); System.out.println("笔记本电脑"); } } public class Client { public static void main(String[] args) { Computer c1=new Disktop(new Asus()); c1.sale(); system.out.println("--------"); Computer c2=new Laptop(new Lenovo()); c2.sale(); } }
输出结果:
asus产品
台式机电脑
--------
lenovo产品
笔记本电脑
组合模式
使用场景:
把部分和整体的关系用树形结构来表示,从而使客户端可以使用统一的方式处理部分对象和整体对象
核心概念:
抽象构建角色:定义了叶子和容器的共同特点;
叶子构建角色:无子节点;
容器构建角色:有容器特征,可以包含子节点;
组合模式工作流程:
-- 在面向系统中,我们常会遇到一类具有“容器”特征的对象,即他们在充当对象的同时,又是其他对象的容器,当对这类对象进行处理时,将会面临复杂的递归问题。
-- 组合模式未处理这种树形结构提供了完美的解决方案,描述了如何将容器和叶子进行递归组合,使得用户在使用时可以一致性的对待容器和叶子
-- 当容器对象的制定方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员,并调用执行,其中,使用了递归调用的机制都整个结构进行处理
实现案例UML:
代码:
public interface AbstractFile { void killVirus();//杀毒 } public class ImageFile implements AbstractFile { private String name; public ImageFile(String name) { super(); this.name = name; } @Override public void killVirus() { System.out.println("--图像文件:"+name+",进行查杀!"); } } public class TextFile implements AbstractFile { private String name; public TextFile(String name) { super(); this.name = name; } @Override public void killVirus() { System.out.println("--文本文件:"+name+",进行查杀!"); } } public class VideoFile implements AbstractFile { private String name; public VideoFile(String name) { super(); this.name = name; } @Override public void killVirus() { System.out.println("--视频文件:"+name+",进行查杀!"); } } public class Folder implements AbstractFile{ private String name; //定义容器,用来存放容器下的子节点 private List<AbstractFile> list=new ArrayList<AbstractFile>(); public Folder(String name) { super(); this.name = name; } public void add(AbstractFile a) { list.add(a); } public void remove(AbstractFile a) { list.remove(a); } public AbstractFile getChild(int index) { return list.get(index); } @Override public void killVirus() { System.out.println("--文件夹"+name+"正在查杀!"); for (AbstractFile file : list) { file.killVirus();//递归 } } } public class Client { public static void main(String[] args) { AbstractFile f2,f3,f4,f5; Folder f1=new Folder("我的收藏"); f2=new TextFile("adada.txt"); f3=new ImageFile("ta.jpg"); //将f2,f3添加到文件夹 f1.add(f2); f1.add(f3); Folder f11=new Folder("电影"); f4=new VideoFile("哈利波特1"); f5=new VideoFile("哈利波特2"); f11.add(f4); f11.add(f5); f1.add(f11); f1.killVirus(); } }
结果:
--文件夹我的收藏正在查杀!
--文本文件:adada.txt,进行查杀!
--图像文件:ta.jpg,进行查杀!
--文件夹电影正在查杀!
--视频文件:哈利波特1,进行查杀!
--视频文件:哈利波特2,进行查杀!
在主方法中,我们将f1作为顶级文件夹,将文本,图像,和其他文件夹存放至此,当f1.killVirus()方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员,并调用执行,其中,使用了递归调用的机制都整个结构进行处理
装饰模式
装饰模式的作用:
动态的为一个对象增加新功能。
装饰模式是一种用于替代继承的技术,无需通过继承增加子类就可以扩展对象的新功能。适用对象的关联关系代替继承关系,更加灵活,同时避免类型体系快速膨胀。
该模式的实现细节:
抽象构建角色:真实对象和装饰对象有相同的接口,这样,客户端对象就能够以与真实对象相同的方式同装饰对象交互。
真实对象:具体的构建角色;
装饰角色:持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实对象,这样1就能在真实对象调用前后增加新的功能。
具体装饰角色:负责给构件对象增加新的责任。
下面是装饰模式的小demo:
UML:
代码:
//抽象构件角色 public interface ICar { void move(); } //具体构建角色 class Car implements ICar{ @Override public void move() { System.out.println("陆地车~~~"); } } //装饰角色 class SuperCar implements ICar{ private ICar car; public SuperCar(ICar car) { super(); this.car = car; } @Override public void move() { // TODO Auto-generated method stub car.move(); } } //具体装饰角色 class WaterCar extends SuperCar{ public WaterCar(ICar car) { super(car); // TODO Auto-generated constructor stub } public void swim() { System.out.println("增加潜水功能~~"); } public void move() { super.move(); swim(); } } class FlyCar extends SuperCar{ public FlyCar(ICar car) { super(car); // TODO Auto-generated constructor stub } public void fly() { System.out.println("增加飞的功能~~"); } public void move() { super.move(); fly(); } } class AiCar extends SuperCar{ public AiCar(ICar car) { super(car); // TODO Auto-generated constructor stub } public void autoMove() { System.out.println("增加自动驾驶功能~·"); } public void move() { super.move(); autoMove(); } } public class Client { public static void main(String[] args) { Car car=new Car(); car.move(); System.out.println("增加新功能-----------------天上飞"); FlyCar fCar=new FlyCar(car); fCar.move(); System.out.println("增加新功能-----------------潜水"); WaterCar wCar=new WaterCar(fCar); wCar.move(); //将一个车增加自动驾驶和飞的功能 System.out.println("将一个新车增加自动驾驶和飞的功能"); AiCar afCar=new AiCar(new FlyCar(new Car())); afCar.move(); } }
结果:
陆地车~~~
增加新功能-----------------天上飞
陆地车~~~
增加飞的功能~~
增加新功能-----------------潜水
陆地车~~~
增加飞的功能~~
增加潜水功能~~
将一个新车增加自动驾驶和飞的功能
陆地车~~~
增加飞的功能~~
增加自动驾驶功能~·
外观模式
核心:
为子系统提供统一的入口。封装子系统的复杂性,便于客户调用端调用。
外观模式实际上就是让客户知道的内容最少,比方说,客户使用一个功能,它不需要彻底了解这个功能,我们只需要提供一个入口,让他可以是使用这个功能即可。
在前面适配器模式,我们进行类适配器与对象适配器作比较时,为了简化主方法的复杂度,封装了两者方法,这就是外观模式;
代码如下:
public class UserEntry { //对象适配器调用 public void objectAdapter() { Client client=new Client(); Charger charger=new Charger(); Target adapter=new Adapter(charger); client.test(adapter); } //类适配器调用 public void classAdapter() { Client client=new Client(); Charger charger=new Charger(); Target adapter=new Adapter2(); client.test(adapter); } } //插座, public class Client { public void test(Target t) { t.shipei(); } public static void main(String[] args) { new UserEntry().objectAdapter(); System.out.println("---------"); new UserEntry().classAdapter(); } }
享元模式
使用场景:
内存属于稀缺资源,不要随便浪费,如果有很多个完全相同或相似的对象,我们可以通过享元模式,节省内存。
核心:享元模式以共享的方式高效的支持大量细粒度对象的重用。
享元模式实现:
-享元工厂类:创建并管理享元对象,享元池一般设计成键值对
-抽象享元类:通常是一个抽象类或接口声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态
-具体享元类:为内部状态提供成员变量进行存储
-非共享享元类:不能被共享的子类可以设计为非共享享元类
优点:
极大减少内存中对象的数量
相同或相似对象内存中只存一份,极大的节约资源,提高系统性能
外部状态比较独立,不影响内部状态
缺点:
模式较为复杂,使程序逻辑复杂化
为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长。用时间换取了空间
代理模式
作用:
通过代理,控制对对象的访问
可以详细控制访问某个对象的方法,在调用这个方法钱做前置处理,调用这个方法后后置处理(也就是功能增强)
静态代理
UML:
代码:
public interface Star { /** * 授予 */ void confer(); /** * 签合同 */ void signContract(); /** * 订票 */ void bookTick(); /** * 跳舞 */ void dance(); /** * 唱歌 */ void sing(); } public class RealStar implements Star{ @Override public void confer() { System.out.println("RealStar.confer()"); } @Override public void signContract() { System.out.println("RealStar.signContract()"); } @Override public void bookTick() { System.out.println("RealStar.bookTick()"); } @Override public void dance() { System.out.println("RealStar(明星本人).dance()"); } @Override public void sing() { System.out.println("RealStar(明星本人).sing()"); } } //代理对象 public class ProxyStar implements Star { private Star star; public ProxyStar(Star star) { super(); this.star = star; } @Override public void confer() { System.out.println("ProxyStar.confer()"); } @Override public void signContract() { System.out.println("ProxyStar.signContract()"); } @Override public void bookTick() { System.out.println("ProxyStar.bookTick()"); } @Override public void dance() { star.dance(); } @Override public void sing() { star.sing(); } } public class Client { public static void main(String[] args) { //创建真实对象 Star realStar=new RealStar(); //创建代理对象 Star proxyStar=new ProxyStar(realStar); proxyStar.confer(); proxyStar.dance(); proxyStar.sing(); } }
结果:
ProxyStar.confer()
RealStar(明星本人).dance()
RealStar(明星本人).sing()
动态代理执行流程:
代码:
public interface Star { /** * 授予 */ void confer(); /** * 签合同 */ void signContract(); /** * 订票 */ void bookTick(); /** * 跳舞 */ void dance(); /** * 唱歌 */ void sing(); } public class RealStar implements Star{ @Override public void confer() { System.out.println("RealStar.confer()"); } @Override public void signContract() { System.out.println("RealStar.signContract()"); } @Override public void bookTick() { System.out.println("RealStar.bookTick()"); } @Override public void dance() { System.out.println("RealStar(明星本人).dance()"); } @Override public void sing() { System.out.println("RealStar(明星本人).sing()"); } } public class StarHandler implements InvocationHandler { Star realStar; public StarHandler(Star realStar) { super(); this.realStar = realStar; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("授权,订票,签合同"); if(method.getName().equals("sing")) { method.invoke(realStar,args); }else if (method.getName().equals("dance")) { method.invoke(realStar,args); } System.out.println("后续功能增强"); return null; } } public class Client { public static void main(String[] args) { // TODO Auto-generated method stub Star realStar=new RealStar(); StarHandler handler=new StarHandler(realStar); Star proxyStar=(Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class},handler); proxyStar.sing(); } }
结果:
授权,订票,签合同
RealStar(明星本人).sing()
后续功能增强
动态代理会自动创建代理对象,创建的代理对象,完成功能底层调用都是StarHandler的invoke方法
物理视图
物理视图对应用本身的实现结构建模,如将其组织为构件和在运行结点上进行配置。这些视图提供了将类映射至构件和结点的机会。
物理视图有两种:实现试图和配置试图
实现试图对模型中的构建建模,即应用程序搭建的软件单元;以及构件之间的依赖,从而可以估计所预计的到的更改的影响。它还对和其他元素至构件的分配建模
配置视图表达了运行时段构件实例在结点实例中的分布。结果是运行资源,如计算机,设备或内存。该视图允许分布式的结果和资源分配被评估。
模型管理试图
模型管理试图对模型本身的组织建模。模型由一系列包含模型元素的包构成。包可以包含其它包:因此,模型只派了一个根包,简介包含了模型的所有内容。包是操纵包内容,以及访问控制和配置控制的单元。每个模型元素被包或其他元素所拥有。
模型是某个视角、给定精度的对系统的完整描述。因此,可能存在不同视角下的多个模型--例如,分析模型和设计模型。模型显示为特殊的包。
子系统是另外一种特殊的包。他代表了系统的一部分,并具有明晰的接口,接口可以实现为独特的构件。
模型管理信息常在类图中出现。