共计 5424 个字符,预计需要花费 14 分钟才能阅读完成。
ps:本文系转载文章,浏览原文可获取源码,文章开端有原文链接
ps:这一篇是写桥接模式、组合模式和享元模式
1、桥接模式
形象局部与它的实现局部进行独立,让他们进行独立变动;将继承关系转变成组合关系,使得形象和实现这两个的耦合度升高了,缩小了代码量。
桥接模式有以下几个角色:
(1)抽象化角色:定义一个抽象类或者一般类,它的一个属性持有一个对实现化对象。
(2)扩大抽象化角色:抽象化角色的子类,实现父类中的形象办法或者重写父类办法,在构造方法调用父类结构传递实现化角色,使得调用实现化角色中的业务办法是采纳组合关系来实现。
(3)实现化角色:定义实现化角色的接口,给抽象化角色所调用。
(4)具体实现化角色:实现实现化角色的接口。
上面用桥接模式通过代码来举例一下:
(1)实现化角色,写一个 Brand 接口:
public interface Brand {
public void sale();
}
(2)具体实现化角色,写一个 Lenovo 类并实现 Brand 接口:
class Lenovo implements Brand {
@Override
public void sale() {
System.out.print("联想");
}
}
(3)具体实现化角色,写一个 Shenzhou 类并实现 Brand 接口:
class Shenzhou implements Brand {
@Override
public void sale() {
System.out.print("神舟");
}
}
(4)抽象化角色,写一个 Computer 类:
public class Computer {
public Brand brand;
public Computer(Brand brand) {this.brand = brand;}
public void sale() {brand.sale();
}
}
(5)扩大抽象化角色,写一个 Desktop 类并继承 Computer 类:
class Desktop extends Computer {
public Desktop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
System.out.println("台式机");
}
}
(6)扩大抽象化角色,写一个 Laptop 类并继承 Computer 类:
class Laptop extends Computer {
public Laptop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
System.out.println("笔记本");
}
}
(7)客户端进行测试调用:
Computer computer = new Desktop(new Shenzhou());
computer.sale();
Computer computer2 = new Desktop(new Lenovo());
computer2.sale();
日志打印如下所示:
形象局部与它的实现局部进行独立就好比例子中的 Desktop 和 Shenzhou 独立开来;将继承关系转变成组合关系就好比 Computer 的子类和 Brand 子类进行组合。
桥接模式的实现细节既能够客户通明也能够对用户暗藏,设计出了比继承更好的思维,可能做到拆散形象和实现;因为聚合关联关系建设在形象层,所以给开发者了解起来没那么容易以及减少肯定的设计难度;两个维度独立的变动,所以应用范畴内具备肯定的局限性。
2、组合模式
一种将对象组合成树状的层次结构的模式,形容整体与局部的关系,使得用户对单个对象和组合对象的应用具备一致性;它是把对象组合到树形构造中,顶层的节点被称为根节点,根节点上面又蕴含树枝节点和叶子节点,树枝节点上面又能够呈现树枝节点和叶子节点;就好比文件夹,根文件夹上面还有子文件夹和文件,子文件夹上面还有文件夹和文件。
组合模式具备以下几个角色:
(1)形象构件角色:为树叶构件和树枝构件申明一个公同的接口,给它们的默认行为进行实现。
(2)树叶构件角色:叶子节点对象,它没有子节点,形象构件角色的子类,就好比电脑中的文件。
(3)树枝构件角色:分支节点对象,它有子节点,形象构件角色的子类,就好比电脑中的文件夹存储和治理子文件夹和子文件。
上面用代码来进行举例并演示:
(1)形象构件角色,写一个 AbstractFile 接口:
public interface AbstractFile {
public void killVirus();
}
(2)树叶构件角色,写一个 ImageFile 类并实现 AbstractFile 接口:
class ImageFile implements AbstractFile {
private String name;
public ImageFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("图片文件" + name + "查杀");
}
}
(3)树叶构件角色,写一个 TextFile 类并实现 AbstractFile 接口:
class TextFile implements AbstractFile {
private String name;
public TextFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("文本文件" + name + "查杀");
}
}
(4)树叶构件角色,写一个 VideoFile 类并实现 AbstractFile 接口:
class VideoFile implements AbstractFile {
private String name;
public VideoFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("视频文件" + name + "查杀");
}
}
(5)树枝构件角色,写一个 Folder 类并实现 AbstractFile 接口:
class Folder implements AbstractFile {
private String name;
private List<AbstractFile> list = new ArrayList<AbstractFile>();
public Folder(String name) {
this.name = name;
}
public void add(AbstractFile file) {
list.add(file);
}
public void remove(AbstractFile file) {
list.remove(file);
}
public AbstractFile get(int index) {
return list.get(index);
}
@Override
public void killVirus() {
System.out.println("文件夹" + name + "查杀");
for (AbstractFile file: list) {file.killVirus();
}
}
}
客户端进行调用测试:
AbstractFile f2,f3,f4,f5;
Folder f1 = new Folder("我的文件夹");
f2 = new ImageFile("我的图片");
f3 = new TextFile("我的文本文件");
f1.add(f2);
f1.add(f3);
Folder f11 = new Folder("我的电影");
f4 = new VideoFile("神雕侠侣");
f5 = new VideoFile("笑傲江湖");
f11.add(f4);
f11.add(f5);
f1.add(f11);
f1.killVirus();
日志打印如下所示:
这里是模拟电脑查杀文件的过程,从这里看出,f1 相当于根目录,f2 和 f3 是 f1 目录下的文件,f11 是 f1 目录下的文件夹,而 f11 又蕴含了 f4 和 f5 这 2 个文件。
客户端代码能够全副解决单个对象和组合对象,毋庸关怀组合对象与单个对象的不同,而可能对立地应用组合构造中的所有对象;在组合体内退出新的对象,客户端中不会更改原有的代码;然而客户端须要花工夫分清类之间的档次关系,限度容器中的构件也有肯定的难度。
3、享元模式
通过共享的技术让多个雷同的对象不用每个都去实例化一个对象,只须要共享一份就能够了,这样防止大量类似类的开销,从而进步系统资源的利用率。
享元模式具备以下几种角色:
(1)形象享元角色:具体享元角色的父类,给子类提供标准须要实现的接口。
(2)具体享元角色:形象享元角色的子类,实现形象享元角色中标准的接口。
(3)非享元角色:内部不可共享的状态,它作为享元角色办法中的参数。
(4)享元工厂角色:创立和存储享元角色,当客户端申请创立一个享元对象时,它就会查看是否有符合要求的享元对象,如果有就从存储中拿进去;如果没有就创立一个新的享元对象并存储起来。
咱们以五子棋为例子,五子棋中的黑白棋子,它们尽管坐标点不同,然而色彩就只分为 2 种,雷同色彩的棋子共用一种色彩,不用再创立一个同种色彩的对象;上面用代码进行演示一下:
(1)形象享元角色,写一个 ChessFlyWeight 接口:
public interface ChessFlyWeight {
public void setColor(String c);
public String getColor();
public void display(Coordinate c);
}
(2)具体享元角色,写一个 ConcreteChess 类并实现 ChessFlyWeight 接口:
class ConcreteChess implements ChessFlyWeight {
private String color;
public ConcreteChess(String color) {
super();
this.color = color;
}
@Override
public void setColor(String c) {
this.color = c;
}
@Override
public String getColor() {
return color;
}
@Override
public void display(Coordinate c) {
System.out.println("棋子色彩" + color);
System.out.println("棋子地位" + c.getX() + ":" + c.getY());
}
}
(3)非享元角色,写一个 Coordinate 类:
public class Coordinate {
private int x,y;
public Coordinate(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;
}
}
(4)享元工厂角色,写一个 ChessFlyWeightFactotry 类:
public class ChessFlyWeightFactotry {
private static Map<String, ChessFlyWeight> map = new HashMap<String,ChessFlyWeight>();
public static ChessFlyWeight getChess(String color){if (map.get(color) != null) {return map.get(color);
} else {ChessFlyWeight chessFlyWeight = new ConcreteChess(color);
map.put(color, chessFlyWeight);
return chessFlyWeight;
}
}
}
客户端进行测试:
ChessFlyWeight c1 = ChessFlyWeightFactotry.getChess("彩色");
ChessFlyWeight c2 = ChessFlyWeightFactotry.getChess("彩色");
System.out.println(c1);
System.out.println(c2);
System.out.println("减少内部解决 -------------------");
c1.display(new Coordinate(10, 10));
c2.display(new Coordinate(20, 20));
日志打印如下所示:
从这里咱们能够看到,当咱们要两次拿彩色棋子的时候 ChessFlyWeightFactotry 会查看是否有彩色棋子的对象,第一次拿彩色棋子的时候,显著没有彩色棋子就创立一个 ConcreteChess 类对象;当第二次拿的时候,查看到存在彩色的棋子,即 ConcreteChess 类对象,便把 ConcreteChess 类对象拿进去应用,所以 c1 和 c2 是同一个对象,这个有点相似单例模式。
享元模式中领有同一种个性的具体享元对象只存在一个,这大大减少了零碎中对象的数量,缩小了零碎性能的开销;然而不可避免的应用内部不可共享的状态,这给程序设计带来肯定的复杂性。