23种设计模式Java版第四篇
Posted 小二玩编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23种设计模式Java版第四篇相关的知识,希望对你有一定的参考价值。
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 是同一个对象,这个有点类似单例模式。
享元模式中拥有同一种特性的具体享元对象只存在一个,这大大减少了系统中对象的数量,减少了系统性能的开销;但是不可避免的使用外部不可共享的状态,这给程序设计带来一定的复杂性。
以上是关于23种设计模式Java版第四篇的主要内容,如果未能解决你的问题,请参考以下文章