适配器模式、代理模式、桥接模式、装饰模式、组合模式、外观模式、享元模式
核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题。
一、适配器模式(adapter)
1.1、作用:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
1.2、模式中的角色:目标接口(Target)、需要适配的类(Adaptee)、适配器(Adapter)
1.3、UML图:
1.4、示例:
//目标接口(Target),客户所期待所需要的接口
public interface USB {
public void connect();
}
class ComputerUSB implements USB,Serializable{
private String audio;
private String video;
private String electric;
public ComputerUSB(String audio, String video, String electric) {
super();
this.audio = audio;
this.video = video;
this.electric = electric;
}
public String getAudio() {
return audio;
}
public void setAudio(String audio) {
this.audio = audio;
}
public String getVideo() {
return video;
}
public void setVideo(String video) {
this.video = video;
}
public String getElectric() {
return electric;
}
public void setElectric(String electric) {
this.electric = electric;
}
public void connect() {
System.out.println("USB:"+this.video+this.audio+this.electric+"连接上了电脑");
}
}
--------------------------------------------------------------------------------
//需要适配的类(Adaptee),需要把VGA转化为USB
public interface VGA {
public void connect();
}
class ComputerVGA implements VGA,Serializable{
private String audio;
private String video;
private String electric;
public ComputerVGA(String audio, String video, String electric) {
super();
this.audio = audio;
this.video = video;
this.electric = electric;
}
public String getAudio() {
return audio;
}
public void setAudio(String audio) {
this.audio = audio;
}
public String getVideo() {
return video;
}
public void setVideo(String video) {
this.video = video;
}
public String getElectric() {
return electric;
}
public void setElectric(String electric) {
this.electric = electric;
}
public void connect() {
System.out.println("VGA:"+this.video+this.audio+this.electric+"连接上了电脑");
}
}
--------------------------------------------------------------------------------
//适配器(Adapter),通过包装一个需要适配的对象,把原接口转换成目标接口。
public class Adapter extends ComputerVGA implements USB{
public Adapter(String audio, String video, String electric) {
super(audio, video, electric);
}
public void connect() {
super.connect();
}
}
--------------------------------------------------------------------------------
//客户端类
public class Client {
public static void main(String[] args) {
USB usb = new Adapter("音频线", "视频线", "电源线");
usb.connect();
}
}
--------------------------------------------------------------------------------
结果:
VGA:视频线音频线电源线连接上了电脑
--------------------------------------------------------------------------------
总结:原本只能USB接口才能连上电脑,但结果是VGA接口连上了电脑,这是因为通过适配器把原先的VGA接口转化成了原本需要的电脑USB接口。
二、代理模式(Proxy pattern)
2.1、作用:通过代理,控制对对象的访问。可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。(即:AOP的微观实现!)
2.2、UML图:
2.3、示例:
此处略过,详见我的另一篇文章(java代理(静态代理和动态代理): https://www.jianshu.com/p/ed05eef1e60c)
三、桥接模式(bridge)
3.1、作用:处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。它极大的提高了系统可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有的系统,符合开闭原则。
3.2、UML图:
3.3、示例:
//电脑接口
public interface Computer {
public void play();
}
//电脑类
class RealComputer implements Computer{
protected Brand brand;
public RealComputer(Brand brand) {
super();
this.brand = brand;
}
public void play() {
}
}
//桌面电脑类
class DesktopComputer extends RealComputer{
public DesktopComputer(Brand brand) {
super(brand);
}
public void play() {
System.out.println(super.brand.getName()+"桌面电脑开始工作了");
}
}
//笔记本
class LaptopComputer extends RealComputer{
public LaptopComputer(Brand brand) {
super(brand);
}
public void play() {
System.out.println(super.brand.getName()+"笔记本开始工作了");
}
}
--------------------------------------------------------------------------------
//品牌接口
public interface Brand {
public void setName(String name) ;
public String getName();
}
//联想品牌
class LenovoBrand implements Brand{
public String name;
public LenovoBrand() {
super();
this.name="联想";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//华为品牌
class HuaweiBrand implements Brand{
public String name;
public HuaweiBrand() {
super();
this.name="华为";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
--------------------------------------------------------------------------------
public class Client {
public static void main(String[] args) {
Computer c1 = new DesktopComputer(new LenovoBrand());
Computer c2 = new DesktopComputer(new HuaweiBrand());
Computer c3 = new LaptopComputer(new LenovoBrand());
Computer c4 = new LaptopComputer(new HuaweiBrand());
c1.play();c2.play();c3.play();c4.play();
}
}
--------------------------------------------------------------------------------
结果:
联想桌面电脑开始工作了
华为桌面电脑开始工作了
联想笔记本开始工作了
华为笔记本开始工作了
--------------------------------------------------------------------------------
总结:如果出现多个属性组合作为一个对象的唯一标识时(也就是多维度时),用桥接模式,会大大的减少子类的个数,从而降低管理和维护的成本。
四、组合模式(composite)
4.1、作用:把部分和整体的关系用树形结构来表示,从而使客户端可以使用统一的方式处理部分对象和整体对象。组合模式为处理树形结构提供了完美的解决方案。
4.2、关键组成:抽象构件(Component)角色、叶子(Leaf)构件角色、容器(Composite)构件角色
4.3、UML图:
4.4、示例:
//抽象文件
public interface MyFile {
public void printChild();
public String getName();
}
//叶子文件接口
interface LeafFile extends MyFile{
public void printChild();
public String getName();
}
//文件夹接口
interface CompositeFile extends MyFile{
public void printChild();
public String getName();
public void addFile(MyFile myFile);
public void removeFile(MyFile myFile);
}
//文件对象
class MyLeafFile implements LeafFile{
private String name;
public MyLeafFile(String name) {
super();
this.name = name;
}
public void printChild() {
System.out.println(this.name);
}
public String getName() {
return this.name;
}
}
//文件夹对象
class MyCompositeFile implements CompositeFile{
private String name;
private List childFile;
public MyCompositeFile(String name) {
super();
this.name = name;
childFile = new ArrayList();
}
public void printChild() {
//System.out.println("文件夹:"+this.name);
for(MyFile myfile:childFile){
if(myfile instanceof LeafFile){
myfile.printChild();
}else if(myfile instanceof CompositeFile){
myfile.printChild();
}
}
}
public String getName() {
return null;
}
public void addFile(MyFile myFile){
childFile.add(myFile);
}
public void removeFile(MyFile myFile){
childFile.remove(myFile);
}
}
--------------------------------------------------------------------------------
public class Client {
public static void main(String[] args) {
MyFile f1 = new MyLeafFile("文件1.txt");
MyFile f2 = new MyLeafFile("文件2.avi");
MyFile f3 = new MyLeafFile("文件3.mp4");
MyFile f4 = new MyLeafFile("文件4.rar");
CompositeFile f5 = new MyCompositeFile("文件夹1");
CompositeFile f6 = new MyCompositeFile("文件夹2");
CompositeFile f7 = new MyCompositeFile("文件夹3");
f5.addFile(f1);f5.addFile(f2);
f6.addFile(f3);f6.addFile(f5);
f7.addFile(f6);f7.addFile(f4);
f7.printChild();
}
}
--------------------------------------------------------------------------------
结果:
文件3.mp4
文件1.txt
文件2.avi
文件4.rar
--------------------------------------------------------------------------------
总结:组合模式,天生有迭代特性,适合树状关系对象的处理
五、装饰模式(decorator)
5.1、作用:能够动态的为一个对象增加新的功能,是一种用于代替继承的技术
5.2、关键组成:Component抽象构件角色、ConcreteComponent 具体构件角色(真实对象)、Decorator装饰角色、ConcreteDecorator具体装饰角色
5.3、UML图:
5.4、示例:
//电脑接口
public interface Computer {
public void play();
}
//普通电脑类
class MyComputer implements Computer{
public void play() {
System.out.println("普通电脑");
}
}
//适配电脑类(中继的作用)
class SuperComputer implements Computer{
protected Computer computer;
public SuperComputer(Computer computer) {
super();
this.computer = computer;
}
public void play() {
computer.play();
}
}
//游戏机
class GamerComputer extends SuperComputer{
public GamerComputer(Computer computer) {
super(computer);
}
public void gamer(){
System.out.println("我能打游戏");
}
public void play() {
super.computer.play();
gamer();
}
}
//办公机
class OfficeComputer extends SuperComputer{
public OfficeComputer(Computer computer) {
super(computer);
}
public void office(){
System.out.println("我能办公");
}
public void play() {
super.computer.play();
office();
}
}
--------------------------------------------------------------------------------
public class Client {
public static void main(String[] args) {
Car car =new Car();
car.move();
System.out.println("------------");
FlyCar flyCar = new FlyCar(car);
flyCar.move();
System.out.println("------------");
AICar aiCar = new AICar(car);
aiCar.move();
System.out.println("------------");
AICar aiCar2 = new AICar(flyCar);
aiCar2.move();
}
}
--------------------------------------------------------------------------------
结果:
普通电脑
------------
普通电脑
我能打游戏
------------
普通电脑
我能办公
------------
普通电脑
我能打游戏
我能办公
--------------------------------------------------------------------------------
总结:装饰模式可以不通过多层继承自由给指定对象增加新功能
六、外观模式(facade)
6.1、作用:为子系统提供统一的入口。封装子系统的复杂性,便于客户端调用。
6.2、UML图:
6.3、示例:
public interface 工商局 {
public void 填写申请();
}
class 武汉工商局 implements 工商局{
public void 填写申请() {
System.out.println("填写完了注册公司的申请单");
}
}
--------------------------------------------------------------------------------
public interface 银行 {
public void 缴费();
}
class 武汉银行 implements 银行{
public void 缴费() {
System.out.println("银行缴费成功");
}
}
--------------------------------------------------------------------------------
public interface 税务局 {
public void 交税();
}
class 武汉税务局 implements 税务局{
public void 交税() {
System.out.println("税务局交税成功");
}
}
--------------------------------------------------------------------------------
public class Facade类 {
public void 注册(){
工商局 gsj = new 武汉工商局();
银行 yh = new 武汉银行();
税务局 swj = new 武汉税务局();
gsj.填写申请();
yh.缴费();
swj.交税();
}
}
--------------------------------------------------------------------------------
public class 客户端 {
public static void main(String[] args) {
Facade类 f = new Facade类();
f.注册();
}
}
--------------------------------------------------------------------------------
结果:
填写完了注册公司的申请单
银行缴费成功
税务局交税成功
--------------------------------------------------------------------------------
总结:通过外观模式,把复杂的注册封装为一个体系,暴露出一个Facade类供客户端使用,客户端只用与Facade类打交道,大大降低了客户端的调用复杂度
七、享元模式(FlyWeight)
7.1、作用:享元模式以共享的方式高效地支持大量细粒度对象的重用。
7.2、关键组成:FlyweightFactory享元工厂类、FlyWeight抽象享元类、ConcreteFlyWeight具体享元类、UnsharedConcreteFlyWeight非共享享元类
7.3、优点:a、极大减少内存中对象的数量;b、相同或相似对象内存中只存一份,极大的节约资源,提高系统性能;c、外部状态相对独立,不影响内部状态。
7.4、缺点:a、模式较复杂,使程序逻辑复杂化;b、为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态
使运行时间变长。用时间换取了空间。
7.5、UML图:
7.6、示例:
public interface 棋子 {
public 棋子特性 getCharacter();
public void setCharacter(棋子特性 character);
public 坐标 getCoordinate();
public void setCoordinate(坐标 coordinate);
public void display();
}
class 围棋棋子 implements 棋子{
private 棋子特性 character; //ConcreteFlyWeight具体享元类
private 坐标 coordinate; //UnsharedConcreteFlyWeight非共享享元类
public 围棋棋子(棋子特性 character) {
super();
this.character = character;
}
public 围棋棋子(棋子特性 character, 坐标 coordinate) {
super();
this.character = character;
this.coordinate = coordinate;
}
public 棋子特性 getCharacter() {
return character;
}
public void setCharacter(棋子特性 character) {
this.character = character;
}
public 坐标 getCoordinate() {
return coordinate;
}
public void setCoordinate(坐标 coordinate) {
this.coordinate = coordinate;
}
public void display() {
System.out.println("将"+character.getColor()+"棋子放置到 (X:"+coordinate.getX()+";Y:"+coordinate.getY()+")处");
}
}
--------------------------------------------------------------------------------
//可共享的对象
public class 棋子特性 {
private String color;//颜色
private String shape;//形状
private String material;//材料
public 棋子特性(String color) {
super();
this.color = color;
this.shape = "圆形";
this.material = "木头";
}
public 棋子特性(String color, String shape, String material) {
super();
this.color = color;
this.shape = shape;
this.material = material;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getShape() {
return shape;
}
public void setShape(String shape) {
this.shape = shape;
}
public String getMaterial() {
return material;
}
public void setMaterial(String material) {
this.material = material;
}
}
--------------------------------------------------------------------------------
//不可共享的对象
public class 坐标 {
private int x;
private int y;
public 坐标(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
};
}
--------------------------------------------------------------------------------
public class 享元工厂 {
private static HashMap hm = new HashMap();//存储共享对象
public static 棋子 getChess(String color){
if(hm.get(color)!=null){
棋子 newChess = new 围棋棋子(hm.get(color));
return newChess;
}else{
棋子特性 character = new 棋子特性(color);
棋子 newChess = new 围棋棋子(character);
hm.put(color, character);
return newChess;
}
}
}
--------------------------------------------------------------------------------
public class 客户端 {
public static void main(String[] args) {
围棋棋子 chess1 = (围棋棋子) 享元工厂.getChess("黑色");
围棋棋子 chess2 = (围棋棋子) 享元工厂.getChess("黑色");
System.out.println(chess1.getCharacter());
System.out.println(chess2.getCharacter());
chess1.setCoordinate(new 坐标(10,10));
chess1.display();
chess2.setCoordinate(new 坐标(20,20));
chess2.display();
chess1.display();
}
}
--------------------------------------------------------------------------------
结果:
com.primeton.GOF23.FlyWeight.棋子特性@24c21495
com.primeton.GOF23.FlyWeight.棋子特性@24c21495
将黑色棋子放置到 (X:10;Y:10)处
将黑色棋子放置到 (X:20;Y:20)处
将黑色棋子放置到 (X:10;Y:10)处
--------------------------------------------------------------------------------
总结:此处一定要注意共享的对象与非共享对象的划分,此处是棋子的特性共享,坐标不共享,多个棋子本身是多个对象,只是棋子里面的特性是共享对象,关于这个设计模式的讲解,我个人之前查看过很多文章和教学视频,发现很多讲解着都弄错了(大量的人把棋子本身进行缓存共享了)