23种设计模式——结构型模型
结构型模型的核心作用是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题
public interface Target {
void handleReq();
}
然后准备被适配的类
/**
* 被适配的类
*/
public class Adaptee {
public void request() {
System.out.println("可以完成客户请求的需要功能!");
}
}
然后就是适配器
适配器适配被适配的类有两种方式:
- 一种是直接继承被适配的类,该方式的缺点是java只能单继承,无法完成适配多个类
- 第二种是使用对象组合的方式
方式一
/**
* 适配器本身
* 需要把被适配对象Adaptee跟目标对象Target连接起来
*/
public class Adapter extends Adaptee implements Target {
@Override
public void handleReq() {
super.request();
}
}
方式二
/**
* 适配器本身
* 需要把被适配对象Adaptee跟目标对象Target连接起来
*/
public class Adapter2 implements Target {
private Adaptee adaptee;
public Adapter2(Adaptee adaptee) {
super();
this.adaptee = adaptee;
}
@Override
public void handleReq() {
adaptee.request();
}
}
使用
Target t = new Adapter(); t.handleReq();
-
-
java.io.InputStreamReader(InputStream)
-
java.io.OutputStreamWriter(OutputStream)
作用:通过代理,控制对对象的访问。在调用某个方法前做前置处理,调用这个方法后做后置处理
-
抽象角色:定义代理角色和真实角色的公共对外方法
-
真实角色:实现抽象角色,定义真实角色要实现的业务逻辑
-
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并且可以附加自己的操作
分类:
-
静态代理(静态定义代理类)
-
动态代理(动态生成代理类)
public interface Star {
/**
* 面谈
*/
void confer();
/**
* 签合同
*/
void signContract();
/**
* 订票
*/
void bookTicket();
/**
* 唱歌
*/
void sing();
/**
* 收钱
*/
void collectMoney();
}
真实角色
public class RealStar implements Star {
@Override
public void bookTicket() {
System.out.println("bookTicket");
}
@Override
public void collectMoney() {
System.out.println("collectMoney");
}
@Override
public void confer() {
System.out.println("confer");
}
@Override
public void signContract() {
System.out.println("signContract");
}
@Override
public void sing() {
System.out.println("sing");
}
}
代理角色
public class ProxyStar implements Star {
private Star star; // 被代理的对象
public ProxyStar(Star star) {
this.star = star;
}
@Override
public void bookTicket() {
System.out.println("bookTicket");
}
@Override
public void collectMoney() {
System.out.println("collectMoney");
}
@Override
public void confer() {
System.out.println("confer");
}
@Override
public void signContract() {
System.out.println("signContract");
}
@Override
public void sing() {
// 调用真实角色的方法
star.sing();
}
}
使用
Star star = new ProxyStar(new RealStar()); star.confer(); star.signContract(); star.bookTicket(); star.sing(); star.collectMoney();
动态代理的实现方式
-
JDK自带的动态代理
-
javaassist字节码操作库实现
-
CGLIB
-
ASM(底层使用指令,可维护性较差)
使用JDK自带的动态代理
-
-
该类的作用是动态的生成代理类对象
-
-
java.lang.reflect.InvocationHandler(处理器接口)
-
可以通过invoke方法实现对真实角色的代理访问,所有的流程控制都在这个方法中处理
-
每次通过Proxy生成代理类对象时都要指定对应的处理器对象
-
使用动态代理还是需要实现抽象角色
public interface Star {
/**
* 面谈
*/
void confer();
/**
* 签合同
*/
void signContract();
/**
* 订票
*/
void bookTicket();
/**
* 唱歌
*/
void sing();
/**
* 收钱
*/
void collectMoney();
}
真实角色 这是必须的
public class RealStar implements Star {
@Override
public void bookTicket() {
System.out.println("bookTicket");
}
@Override
public void collectMoney() {
System.out.println("collectMoney");
}
@Override
public void confer() {
System.out.println("confer");
}
@Override
public void signContract() {
System.out.println("signContract");
}
@Override
public void sing() {
System.out.println("sing");
}
}
代理角色
这一块换成了动态代理,需要自定义handler在执行方法前后执行某些操作
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class StarHandler implements InvocationHandler {
private Star realStar;
public StarHandler(Star star) {
this.realStar = star;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
if (method.getName().equals("sing")) {
System.out.println("执行前");
}
// 执行当前方法
obj = method.invoke(realStar, args);
System.out.println("执行后");
return obj;
}
}
使用
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler);
proxy.bookTicket();
proxy.sing();
如果要实现上图中的结构,需要非常复杂的操作,以联想台式机为例,它需要继承台式机类,而台式机类需要实现电脑接口,过程非常的繁琐。
现在通过观察,任意一台笔记本或者是台式机,都由两部分组成,一个是品牌,一个是电脑类型,那么我们可以分别设置两个结构,分别是电脑类型跟品牌,然后将这两个结构联系起来,这中间就像搭了一座桥,所以这种模式叫做桥接模式。
首先是对品牌分类进行定义
/**
* 品牌
*/
public interface Brand {
void sale();
}
class Lenovo implements Brand {
@Override
public void sale() {
System.out.println("联想电脑");
}
}
class Dell implements Brand {
@Override
public void sale() {
System.out.println("戴尔电脑");
}
}
然后对电脑类型进行定义
/**
* 电脑类型
*/
public class Computer {
protected Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public void sale() {
brand.sale();
}
}
class Desktop extends Computer {
public Desktop(Brand b) {
super(b);
}
@Override
public void sale() {
super.sale();
System.out.println("销售台式机");
}
}
class Laptop extends Computer {
public Laptop(Brand b) {
super(b);
}
@Override
public void sale() {
super.sale();
System.out.println("销售笔记本");
}
}
使用
现在想要一个品牌的电脑就不需要定义一个类了,直接组合即可
public static void main(String[] args) {
Computer c = new Laptop(new Lenovo());
c.sale();
}
组合模式用于处理属性结构,不论是处理叶子节点还是容器节点都有一个统一的处理方式
核心组成:
-
抽象构建角色,定义了叶子和容器构建共同遵循的规则,也是供客户端调用的接口
-
叶子构建角色,无子节点
-
容器构建角色,有容器特征,可以包含子节点
/**
* 抽象组件
*/
public interface Component {
void operation();
}
/**
* 叶子组件
*/
interface Leaf extends Component {
}
/**
* 容器组件
*/
interface Composite extends Component {
void add(Component c); // 添加组件
void remove(Component c); // 删除组件
Component getChild(int index); // 返回指定的组件
}
import java.util.ArrayList;
import java.util.List;
/**
* 抽象构建
*/
public interface AbstractFile {
void killVirus(); // 杀毒
}
/**
* 这是叶子节点,因为一个图像文件里面不会再包含别的文件了
*/
class ImageFile implements AbstractFile {
private String name;
public ImageFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("图像文件:" + name + "进行查杀!");
}
}
/**
* 这是叶子节点,因为一个文本文件里面不会再包含别的文件了
*/
class TextFile implements AbstractFile {
private String name;
public TextFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("文本文件:" + name + "进行查杀!");
}
}
/**
* 容器节点,因为一个文件夹下可以有其他的文件
*/
class Folder implements AbstractFile {
private String name;
// 用来存放容器下构建的子节点
private List<AbstractFile> list = new ArrayList<>();
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 getChild(int index) {
return list.get(index);
}
@Override
public void killVirus() {
System.out.println("文件夹: " + name + "进行查杀");
list.forEach(AbstractFile::killVirus);
}
}
使用
public static void main(String[] args) {
Folder f1 = new Folder("我的收藏");
AbstractFile f2, f3;
f2 = new ImageFile("1.jpg");
f3 = new TextFile("HHH.txt");
f1.add(f2);
f1.add(f3);
f1.killVirus();
}
-
动态的为一个对象增加新的功能
-
装饰模式是一种用于替代继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系替代继承关系,更加灵活,同时避免类型体系的快速膨胀
实现细节
-
Component抽象构建角色:真实对象和装饰对象有相同的接口,这样客户端对象就能以与真实对象相同的方式同装饰对象交互
-
ConcreateComponent具体构建角色(真实对象)
-
Decorate装饰角色,持有一个抽象构建的引用,装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象,这样,就能在真实对象调用前后增加新的功能
-
ConcreateDecorate具体装饰角色
/**
* 抽象组件
*/
public interface ICar {
void move();
}
// 真实对象,即被装饰对象
class Car implements ICar {
@Override
public void move() {
System.out.println("陆地上跑!");
}
}
/**
* Decorate装饰器角色
*/
class SuperCar implements ICar {
protected ICar iCar;
public SuperCar(ICar iCar) {
this.iCar = iCar;
}
@Override
public void move() {
iCar.move();
}
}
/**
* ConcreateDecorate具体装饰角色
*/
class FlyCar extends SuperCar {
public FlyCar(ICar iCar) {
super(iCar);
}
public void fly() {
System.out.println("天上飞");
}
@Override
public void move() {
fly();
super.move();
}
}
/**
* ConcreateDecorate具体装饰角色
*/
class WaterCar extends SuperCar {
public WaterCar(ICar iCar) {
super(iCar);
}
public void swim() {
System.out.println("水上游");
}
@Override
public void move() {
swim();
super.move();
}
}
使用
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("继续增加水上跑");
WaterCar waterCar = new WaterCar(flyCar);
waterCar.move();
}
迪米特法则(最少知识原则):一个软件实体应当尽可能少的与其它实体发生相互作用
核心:为子系统提供统一的入口。封装子系统的复杂性,便于客户端调用。
作用:内存属于稀缺资源,不能随意浪费。如果有很多个完全相同或相似的对象,我们可以使用享元模式,节省内存
享元模式的关键是做到了区分内部状态跟外部状态
-
内部状态:可以共享,不会随环境的变化而改变
-
外部状态:不可以共享,会随环境的变化而变化
-
-
Flyweight抽象享元类:通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态
-
ConcreateFlyWeight具体享元类:为内部状态提供成员变量进行存储
-
UnsharedConcreateFlyWeight非共享享元类:不能被共享的子类可以设计为非共享享元类
FlyweightFactory享元工厂
import java.util.HashMap;
import java.util.Map;
/**
* 享元工厂类
*/
public class ChessFlyWeightFactory {
// 享元池
private static Map<String, ChessFlyWeight> map = new HashMap<>();
public static ChessFlyWeight getChess(String color) {
if (map.get(color) != null) {
return map.get(color);
} else {
ChessFlyWeight cfw = new ConcreateChess(color);
map.put(color, cfw);
return cfw;
}
}
}
Flyweight抽象享元类&ConcreateFlyWeight具体享元类
/**
* 享元类
*/
public interface ChessFlyWeight {
void setColor(String color);
String getColor();
void display(Coordinate c);
}
class ConcreateChess implements ChessFlyWeight {
private String color;
public ConcreateChess(String color) {
this.color = color;
}
@Override
public void setColor(String color) {
this.color = color;
}
@Override
public String getColor() {
return color;
}
@Override
public void display(Coordinate c) {
System.out.println("旗子颜色:" + color);
System.out.println("棋子位置:" + c.getX() + ", " + c.getY());
}
}
UnsharedConcreateFlyWeight非共享享元类
/**
* 外部状态UnsharedConcreateFlyWeight
*/
public class Coordinate {
private int x, y;
public Coordinate(int x, int y) {
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 static void main(String[] args) {
ChessFlyWeight c1 = ChessFlyWeightFactory.getChess("黑色");
ChessFlyWeight c2 = ChessFlyWeightFactory.getChess("黑色");
System.out.println(c1);
System.out.println(c2);
System.out.println("增加外部状态的处理==============");
c1.display(new Coordinate(10, 10));
c2.display(new Coordinate(20, 20));
}
-
-
为了节省内存,共享了内存状态,分离出外部状态,而读取外部状态,使运行时间变长。用时间换取了空间


浙公网安备 33010602011771号