学习目标:
常用的几种design pattern
利弊分别是什么?
具体举个例子?
学习内容:
结构型模式:
1、 适配器模式adapter
2、 桥接模式bridge
3、 动态代理模式dynamic proxy
行为型模式:
1、面试被问到observer是什么模式?
学习时间:
1、 周一至周五晚上 7 点—晚上9点学习产出:
1、 视频10+个 2、技术笔记 3 篇1.适配器模式adapter
继承的方式实现适配器
package com.kuang.adapter;
//接口 转换器的抽象实现
//网线插到转化器上
public interface NetToUsb {
void handleRequest();
}
//网线
public class Adaptee {
public void request(){
System.out.println("连接网线上网");
}
}
//1。继承的方式,实现适配器
//连接网线,连接usb
public class Adapter extends Adaptee implements NetToUsb{
@Override
public void handleRequest() {
super.request();//可以上网了
}
}
//client class
public class ClientComputer {
//电脑连上转接器,才可以上网
public void connectNet(NetToUsb adapter){
adapter.handleRequest();
}
public static void main(String[] args) {
ClientComputer clientComputer = new ClientComputer();//电脑
Adaptee adaptee=new Adaptee();//网线
Adapter adapter=new Adapter();//适配器
clientComputer.connectNet(adapter);//电脑连上适配器
}
}
稍作修改,组合的方式实现适配器
//2。组合方式,实现适配器
//连接网线,连接usb
public class Adapter2 implements NetToUsb{
private Adaptee adaptee;
//constructor
public Adapter2(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void handleRequest() {
adaptee.request();//可以上网了
}
}
区别:适配器(adapter2)一端连电脑(clientComputer),一端连网线(adaptee)
//client class
public class ClientComputer {
//电脑连上转接器,才可以上网
public void connectNet(NetToUsb adapter){
adapter.handleRequest();
}
public static void main(String[] args) {
ClientComputer clientComputer = new ClientComputer();//电脑
Adaptee adaptee=new Adaptee();//网线
Adapter2 adapter2=new Adapter2(adaptee);//2.适配器连接网线
clientComputer.connectNet(adapter2);//适配器连上电脑
}
}
优点:适配器可以将多条功能线路,适配到同一个目标接口。
既然可以转换网线,那么再来一条网线的子类,也是可以适配的。
因此,符合里式替换原则,拓展性比较好。
缺点:目标接口只能为接口,不能为类,这点具有一定的局限性。
2.桥接模式bridge
也成为handle & body模式,或者interface模式。专门处理多维度独立变化的情况。
下面例子中,父类/抽象类为桥梁,品牌和类型可以实现自由组装。
苹果+台式机
联想+笔记本
public interface Brand {
void info();
}
public class Apple implements Brand{
@Override
public void info() {
System.out.print("Apple");
}
}
public class Lenovo implements Brand{
@Override
public void info() {
System.out.print("Lenovo");
}
}
public abstract class Computer {
//组合方式,自带brand
protected Brand brand;//子类继承父类,还能用到
public Computer(Brand brand) {
this.brand = brand;
}
public void info() {
brand.info();
}
}
class Destop extends Computer{
public Destop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.print("Destop");
}
}
class Laptop extends Computer {
public Laptop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.print("Laptop");
}
}
public class Test {
public static void main(String[] args) {
Computer computer=new Laptop(new Apple());
computer.info();
Computer computer2=new Destop(new Lenovo());
computer2.info();
}
}
output:
AppleLaptop
LenovoDestop
如果想拓展,比如增加一个Tablet类型,组合起来也很方便。
class Tablet extends Computer {
public Tablet(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.print("Tablet");
}
}
Computer computer3=new Tablet(new Lenovo());
computer3.info();
output:
LenovoTablet
3.代理模式proxy
静态代理 static proxy
不改变原有的代码情况下,另外设置proxy,在proxy里改动和拓展功能。
package com.demo.kuangshen.demo;
public interface Rent {
public void rent();
}
public class Host implements Rent{
@Override
public void rent() {
System.out.print("房东要出租房子");
}
public class Client {
public static void main(String[] args){
//房东要出租房子
Host host=new Host();
// host.rent();
//代理,中介帮房东租房子,一般代理有附属操作
Proxy proxy=new Proxy(host);
//不用面对房东,直接找中介租房
proxy.rent();//背后还是host.rent()
}
}
//代理帮房东
//引入房东组合,
//实现Rent接口
public class Proxy implements Rent{
private Host host;
public Proxy(){
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
host.rent();
}
//看房
public void seeHouse() {
System.out.print("proxy带你看房");
}
//签合同
public void sign() {
System.out.print("proxy带你签合同");
}
//收中介费
public void charge() {
System.out.print("proxy收中介费");
}
}
动态代理 dynamic proxy
动态代理的底层都是反射 reflection
package com.demo.kuangshen.demo.Demo3;
public interface Rent {
public void rent();
}
public class Host implements Rent {
@Override
public void rent() {
System.out.print("房东要出租房子");
}
}
调用reflect包,用invoke来执行方法。
//用这个类,自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;//不同之处:这里是被代理的接口,而不是host
//生成得到代理类
public Object getProxy() {
//getClassLoader,interface,invocationHandler
System.out.println("这是什么?"+this); //com.demo.kuangshen.demo.Demo3.ProxyInvocationHandler@34c45dca
//生成动态代理实例
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//reflect包下的method, |执行接口的方法,参数
seeHouse();
Object res=method.invoke(rent,args);//用invoke来执行方法
charge();
return res;
//动态代理的本质,就是使用反射机制实现
}
public void setRent(Rent rent) {
this.rent=rent;
}
public void seeHouse() {
System.out.println("带房子");
}
public void charge() {
System.out.println("收中介费");
}
}
调用:
public class Client {
public static void main(String[] args){
//真实房东--要出租房子
Host host=new Host();
//代理角色,现在没有
ProxyInvocationHandler pih=new ProxyInvocationHandler();
//通过invocationHandler,处理要调用的接口的对象(代理),
pih.setRent(host);
Rent proxy=(Rent) pih.getProxy();//
proxy.rent();
}
}
//1。 ProxyInvocationHandler pih
//2。 通过pih得到一个 proxy
//3。实现房东要出租房子原始目的
行为型模式:
1.观察者模式observer
模式类似SNS服务,订阅者subscribe了一个主题/消息源,消息源一旦发布消息,订阅者就会收到通知。
定义一对多的关系。当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。
设计模式:观察者模式
张三和赵四王五借钱,承诺有钱还了就通知他们:
具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,违反了面向对象的设计原则。
zhangsan通过Borrower接口 notifyLenders ()
lisi,wangwu通过Lender接口 takeMoney()
package com.kuang.observer;
import java.util.ArrayList;
import java.util.List;
public class ObserverPattern {
public static void main(String[] args) {
Borrower zhangsan=new Zhangsan();
zhangsan.borrow(new Zhaosi());
zhangsan.borrow(new Wangwu());
//一旦状态改变,有钱了,通知多人:
zhangsan.notifyLenders();
}
}
interface Borrower{
void borrow(Lender lender);
void notifyLenders();
}
class Zhangsan implements Borrower{
private List<Lender> allLenders=new ArrayList<>();
// private int state=0;//1是有钱
@Override
public void borrow(Lender lender) {
allLenders.add(lender);
}
@Override
public void notifyLenders() {
allLenders.forEach(lender->lender.takeMoney());
}
}
interface Lender{
void takeMoney();
}
class Zhaosi implements Lender{
@Override
public void takeMoney() {
System.out.println("赵四要钱");
}
}
class Wangwu implements Lender{
@Override
public void takeMoney() {
System.out.println("王五要钱");
}
}
赵四要钱
王五要钱
优点:
1.降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
2.目标与观察者之间建立了一套触发机制。
缺点:
1.目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
2.当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
Thank you for reading !