设计模式--结构型模式
目录代理模式
结构:
- 抽象主题(Subject)类:通过接口或者抽象类声明真实主题和代理对象实现的业务方法
- 真实主题(Real Subject)类:实现抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或拓展真实主题的功能
静态代理
/*
从火车站买票较为麻烦,我们选择从较近的代售点买票。
这里代售点就是 代理类
*/
/**
* @author strind
* @version 1.0
* @description 静态代理
* @date 2024/2/4 15:42
*/
public class Static_proxy {
public static void main(String[] args) {
Proxy_point p = new Proxy_point();
p.sellTicket();
}
}
// 抽象主题
interface SellTicket{
void sellTicket();
}
class Train implements SellTicket{
@Override
public void sellTicket() {
System.out.println("火车站卖票");
}
}
class Proxy_point implements SellTicket{
private Train train = new Train();
@Override
public void sellTicket() {
System.out.println("从代售点秒票");
train.sellTicket();
}
}
jdk动态代理(接口实现原理)
/**
* @author strind
* @version 1.0
* @description jdk动态代理
* @date 2024/2/4 15:50
*/
public class jdk_proxy {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
SellTicket proxy = proxyFactory.getProxy();
proxy.sellTicket();
}
}
interface SellTicket{
void sellTicket();
}
class Train implements SellTicket{
@Override
public void sellTicket() {
System.out.println("火车站卖票");
}
}
class ProxyFactory{
// 要代理的目标对象
private Train target = new Train();
public SellTicket getProxy(){
// 类加载器,接口(代理目标实现的接口),代理对象要处理的程序
return (SellTicket) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
// 代理对象本身,接口中方法的封装,方法参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代售点卖票");
Object obj = method.invoke(target, args);
return obj;
}
}
);
}
}
Cblib动态代理(继承原理)
/**
* @author strind
* @version 1.0
* @description cglib动态代理
* @date 2024/2/4 16:13
*/
public class cglib_proxy {
public static void main(String[] args) {
ProxyFactory p = new ProxyFactory();
Train proxy = p.getProxy();
proxy.sellTicket();
}
}
class Train {
public void sellTicket() {
System.out.println("火车站卖票");
}
}
class ProxyFactory implements MethodInterceptor {
private Train target = new Train();
public Train getProxy(){
Enhancer enhancer = new Enhancer();
// 父类字节码(依赖于继承创建代理)
enhancer.setSuperclass(Train.class);
// 回调函数
enhancer.setCallback(this);
return (Train) enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代售点");
return method.invoke(target, objects);
}
}
注意:有接口就使用jdk动态代理,没接口就使用cglib动态代理
适配器模式
将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作
结构:
- 目标接口:当前系统业务所期待的接口,可以说抽象类或接口
- 适配者类:它是被访问和适配的现存组件库中的组件接口
- 适配器类:它是一个转换器,通过继承或引用适配者对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者
类适配器模式
/*
电脑只能读取sd卡,那么该如何才能让电脑读取tf卡的内容呢?
*/
/**
* @author strind
* @version 1.0
* @description 类适配器
* @date 2024/2/5 9:16
*/
public class Adapter {
public static void main(String[] args) {
Computer computer = new Computer();
// 读sd卡
System.out.println(computer.readSD(new SDCardImpl()));
// 读tf卡
System.out.println(computer.readSD(new ADAdapterTF()));
}
}
class Computer{
// 读取sd卡
public String readSD(SDCard sdCard){
return sdCard.readSD();
}
}
interface SDCard{
String readSD();
void write(String data);
}
class SDCardImpl implements SDCard{
@Override
public String readSD() {
return "SDCard data";
}
@Override
public void write(String data) {
System.out.println("data:" + data + " has inputed");
}
}
// 适配者类接口
interface TFCard{
String readTF();
void writeTF(String data);
}
// 适配者类
class TFCardImpl implements TFCard{
@Override
public String readTF() {
return "TFCard data";
}
@Override
public void writeTF(String data) {
System.out.println("data: " + data + " has imputed");
}
}
// 适配器类
class ADAdapterTF extends TFCardImpl implements SDCard{
@Override
public String readSD() {
System.out.println("read from adapter tf");
return readTF();
}
@Override
public void write(String data) {
System.out.println("write to tf by adapter");
writeTF(data);
}
}
注意:类适配器模式违背了合成复用原则,且只有在目标有接口规范时才能使用(存在SDCard接口),反之不能使用。
对象适配器模式
/**
* @author strind
* @version 1.0
* @description 对象适配器模式
* @date 2024/2/5 9:16
*/
public class Adapter {
public static void main(String[] args) {
Computer computer = new Computer();
// 读sd卡
System.out.println(computer.readSD(new SDCardImpl()));
// 读tf卡
System.out.println(computer.readSD(new ADAdapterTF(new TFCardImpl())));
}
}
class Computer{
// 读取sd卡
public String readSD(SDCard sdCard){
return sdCard.readSD();
}
}
interface SDCard{
String readSD();
void write(String data);
}
class SDCardImpl implements SDCard{
@Override
public String readSD() {
return "SDCard data";
}
@Override
public void write(String data) {
System.out.println("data:" + data + " has inputed");
}
}
// 适配者类接口
interface TFCard{
String readTF();
void writeTF(String data);
}
// 适配者类
class TFCardImpl implements TFCard{
@Override
public String readTF() {
return "TFCard data";
}
@Override
public void writeTF(String data) {
System.out.println("data: " + data + " has imputed");
}
}
// 适配器类
class ADAdapterTF implements SDCard{
private TFCard tfCard;
public ADAdapterTF(TFCard tfCard) {
this.tfCard = tfCard;
}
@Override
public String readSD() {
System.out.println("read from adapter tf");
return tfCard.readTF();
}
@Override
public void write(String data) {
System.out.println("write to tf by adapter");
tfCard.writeTF(data);
}
}
/*
在这里,如果不提供SDCard接口,那么我们可以通过继承SDCardImpl来实现。
上一个案例因为已经继承了TFCardImpl,所以无法继承别的类了。
*/
接口适配器模式
当不希望实现一个接口中所以的方法时,可以创建一个抽象类Adapter,实现所有方法,而此时我们只需要继承该抽象类即可。
装饰者模式
结构:
- 抽象构件(component)角色:定义一个抽象接口以规范准备接受附加责任的对象
- 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责
- 抽象装饰(Decorator)角色:继承或实现抽象构件,并包含具体构件的实例,可以通过其子类拓展具体构件的功能
- 具体装饰(Concrete Decorator)角色:实现抽象装饰角色的相关方法,并给具体构件对象添加附加责任
/**
* @author strind
* @version 1.0
* @description 装饰者模式
* @date 2024/2/5 10:16
*/
public class Decorator {
public static void main(String[] args) {
FastFood friedRice = new FriedRice();
System.out.println(friedRice.getDesc() + " " + friedRice.cost());
// 加一个鸡蛋
friedRice = new Egg(friedRice);
System.out.println(friedRice.getDesc() + " " + friedRice.cost());
// 在加一个鸡蛋
friedRice = new Egg(friedRice);
System.out.println(friedRice.getDesc() + " " + friedRice.cost());
// 在加一个培根
friedRice = new Bacon(friedRice);
System.out.println(friedRice.getDesc() + " " + friedRice.cost());
}
}
// 抽象构件角色
abstract class FastFood{
private float price; // 结构
private String desc; // 描述
public FastFood(float price, String desc) {
this.price = price;
this.desc = desc;
}
public FastFood() {
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public abstract float cost();
}
// 具体构件角色
class FriedRice extends FastFood{
public FriedRice(){
super(10,"炒饭");
}
@Override
public float cost() {
return getPrice();
}
}
// 具体构件角色
class FriedNoodle extends FastFood{
public FriedNoodle(){
super(15,"炒面");
}
@Override
public float cost() {
return getPrice();
}
}
// 装饰者类 (抽象装饰者角色)
abstract class Garnish extends FastFood{
private FastFood fastFood;
Garnish(FastFood fastFood,float price, String desc) {
super(price, desc);
this.fastFood = fastFood;
}
public FastFood getFastFood() {
return fastFood;
}
public void setFastFood(FastFood fastFood) {
this.fastFood = fastFood;
}
}
// 具体的装饰者角色
class Egg extends Garnish{
Egg(FastFood fastFood) {
super(fastFood, 1, "鸡蛋");
}
@Override
public float cost() {
return getPrice() + getFastFood().cost();
}
@Override
public String getDesc() {
return super.getDesc() + " " + getFastFood().getDesc();
}
}
class Bacon extends Garnish{
Bacon(FastFood fastFood) {
super(fastFood, 2, "培根");
}
@Override
public float cost() {
return getPrice() + getFastFood().cost();
}
@Override
public String getDesc() {
return super.getDesc() + " " + getFastFood().getDesc();
}
}
使用场景:
-
当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
不能采用继承的情况主要有两大类
- 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类的数目呈现爆炸性增长
- 第二类是因为类定义不能继承(final)
-
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
-
当对象的功能要求可以动态的添加,也可以在动态的撤销
静态代理与装饰者模式的区别:
-
相同点:
- 都要实现与目标类相同的业务接口
- 在两个类中都要声明目标对象
- 都可以在不修改类的前提下增强目标方法
-
不同点:
-
目的不同
装饰者是为了增强目标对象
静态代理是为了保护和隐藏目标对象
-
获取目标对象构建的地方不同
装饰者是由外界传递进来,通过构造/set方法传递
静态代理是在代理类内部创建,以此来隐藏目标对象
-
桥接模式
结构:
- 抽象化角色:定义抽象类,并包含一个对实现化对象的引用
- 扩展抽象化角色:是抽象化角色的子类,实现父类的业务方法,并通过组合关系调用实现化角色中的业务方法
- 实现化角色:定义实现化角色的接口,供扩展抽象角色调用
- 具体实现化角色:给出实现化角色接口的具体实现
/*
两种操作系统播放两种格式的视频
*/
/**
* @author strind
* @version 1.0
* @description 桥接模式
* @date 2024/2/5 11:15
*/
public class bridge {
public static void main(String[] args) {
OperatingSystem system = new Mac(new AVIFile());
system.play("aa");
}
}
// 实现化角色
interface videoFile{
void decode(String fileName);
}
// 具体的实现化角色
class AVIFile implements videoFile{
@Override
public void decode(String fileName) {
System.out.println("avi视频" + fileName);
}
}
// 具体的实现化角色
class RmvbFile implements videoFile{
@Override
public void decode(String fileName) {
System.out.println("Rmvb视频" + fileName);
}
}
// 抽象化角色
abstract class OperatingSystem{
protected videoFile videoFile;
public OperatingSystem(videoFile videoFile) {
this.videoFile = videoFile;
}
abstract void play(String fileName);
}
// 扩展抽象化角色
class Windows extends OperatingSystem{
public Windows(videoFile videoFile) {
super(videoFile);
}
@Override
void play(String fileName) {
videoFile.decode(fileName);
}
}
// 扩展抽象化角色
class Mac extends OperatingSystem{
public Mac(videoFile videoFile) {
super(videoFile);
}
@Override
void play(String fileName) {
videoFile.decode(fileName);
}
}
使用场景
- 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时
- 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时
- 当一个系统需要在构建的抽象角色和具体角色之间增加更多的灵活性时,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使他们在抽象层建立一个关联关系
外观模式
定义:又叫门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。是"迪米特法则"的应用。
结构:
- 外观角色:为多个子系统对外提供一个共同的接口
- 子系统角色:实现系统的部分功能,客户可以通过外观角色访问它
/**
* @author strind
* @version 1.0
* @description 外观模式
* @date 2024/2/5 11:47
*/
public class facade {
public static void main(String[] args) {
SmartApplicationFacade sm = new SmartApplicationFacade();
sm.say("打开家电");
sm.say("关闭家电");
}
}
class Light{
public void on(){
System.out.println("打开电灯");
}
public void off(){
System.out.println("关闭电灯");
}
}
class TV{
public void on(){
System.out.println("打开电视");
}
public void off(){
System.out.println("关闭电视");
}
}
class AirCondition{
public void on(){
System.out.println("打开空调");
}
public void off(){
System.out.println("关闭空调");
}
}
class SmartApplicationFacade{
private Light light;
private TV tv;
private AirCondition airCondition;
public SmartApplicationFacade() {
light = new Light();
tv = new TV();
airCondition = new AirCondition();
}
public void say(String message){
if (message.contains("打开")){
on();
}else if (message.contains("关闭")){
off();
}
}
private void on(){
light.on();
tv.on();
airCondition.on();
}
private void off(){
light.off();
tv.off();
airCondition.off();
}
}
注意:不符合开闭原则,修改很麻烦
组合模式
略
享元模式
定义:运用共享技术来有效地支持大量细粒度对象的复用。提高利用率
例子:jdk中Integer类使用了该模式,-128~127是共享的。
标签:String,--,void,class,println,设计模式,out,public,结构型 From: https://www.cnblogs.com/strind/p/18013750