上篇文章说了,单一职责,接口隔离,里氏替换,依赖倒置,迪米特,开闭原则。
设计模式六大原则
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
适配器模式:
将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由某个接口不匹配所造成的类的兼容性问题。
类的适配器模式,对象的适配器模式,接口的适配器模式。
类的适配器模式 :可以通过多重继承目标接口和被适配者方法来实现适配。当希望一个类转换满足另一个类的新接口时候,可以使用类适配器创建新类继承原有的类。
对象的适配器模式:使用了不同的方法实现适配,对象适配器使用组合,类的适配器使用继承。当希望将一个对象满足另一个新接口对象时,可以创建wrapper类。
接口的适配器模式:当不需要全部接口实现方法时候,可设计一个抽象类实现接口,并为该接口每个方法提供默认的实现方法,那么该抽象子类可以有选择的覆盖父类某些方法来实现,它使用接口不想使用所有方法的情况。
装饰者模式:
定义:动态的将新功能附加到对象上。增加对象功能扩展性,比继承更有弹性。
装饰者和被装饰者之间必须是一样的类型,也就是共同的超类。因为装饰者和被装饰者是同一个类型,因此装饰者可以取代被装饰者,这样就使被装饰者拥有了装饰者独有的行为。根据这个理解,我们可以在任何时候实现新的装饰者增加新的行为。
代理模式:
定义:给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
静态代理:
代码语言:javascript复制public interface BuyBus {
void buyBus();
}
public class BuyBusProxy implements BuyBus{
private BuyService buyService;
BuyBusProxy(BuyService buyService){
this.buyService = buyService;
}
@Override
public void buyBus() {
// 买车前干啥
buyService.buyBus();
// 买车后干啥
}
}
public class BuyService implements BuyBus{
@Override
public void buyBus() {
System.out.println("买车");
}
}
优点:复合开闭原则对代码扩展的情况下不修改原有的代码。
缺点:每次都需要新增代理类,工作量大,代码多,一旦改变代理类也要改变。
动态代理:
利用jdk的api来实现代理对象的生成,动态的在内存中构建代理对象,代理的类不需要实现接口,但是要求被代理的对象必须有接口。
代码语言:javascript复制public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
System.out.println("执行前");
Object result = method.invoke(object, args);
System.out.println("执行后");
return result;
}
}
public static void main(String[] args) {
BuyServiceImpl buyServiceImpl = new BuyServiceImpl();
BuyBusService proxyBuy =(BuyBusService) Proxy.newProxyInstance(BuyBusService.class.getClassLoader(),
new Class[]{BuyBusService.class}, new DynamicProxyHandler(buyServiceImpl));
proxyBuy.buyBus();
}
动态代理相对于静态代理,节俭了很多代码,提高了复用性,但一样依赖于接口。
cglib代理
动态生成一个要代理的子类,子类重写要代理类的所有不是final方法,子类中采用方法拦截技术拦截所有父类方法调用,横切逻辑,优于jdk动态代理。
缺点是对final方法无法进行代理。
代码语言:javascript复制public class CglibProxy implements MethodInterceptor {
private Object object;
public Object getInstance(Object object){
this.object = object;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.object.getClass());
enhancer.setCallback(this);
return enhancer;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行前准备");
Object result = methodProxy.invoke(o,objects);
System.out.println("执行后准备");
return result;
}
}
public static void main(String[] args) {
BuyBusService buyBusService = new BuyServiceImpl();
CglibProxy cglibProxy = new CglibProxy();
BuyServiceImpl proxyBuy = (BuyServiceImpl)cglibProxy.getInstance(buyBusService);
proxyBuy.buyBus();
}
cglib的性能比jdk动态代理性能更好,但是cglib创建对象比jdk创建对象耗时更多,所以单例模式下,无需频繁创建对象用cglib更合适,而且cglib因为动态创建子类,所以final修饰的无法代理。
外观模式
隐藏系统的复杂性,并且向客户端提供一个可以访问的接口。
核心的功能就是门面角色 整合所有子系统角色,方便外部统一访问。
代码语言:javascript复制public class Fang {
private Deng deng;
private Door door;
public void open(){
System.out.println("进入房间");
deng.open();
door.open();
}
public void close(){
System.out.println("出去房间");
deng.close();
door.close();
}
}
public class Door {
public void open(){
System.out.println("开门");
}
public void close(){
System.out.println("关门");
}
}
public class Deng {
public void open(){
System.out.println("开灯");
}
public void close(){
System.out.println("关灯");
}
}
外观模式优点是访问对于客户端更简洁明了,不需要在乎他内部调用多少服务。
桥接模式
定义:将抽象部分与它的实现部分分离,使他们可以独立变化。
代码语言:javascript复制
public interface Software {
public void run();
}
public abstract class Phone {
public abstract void run();
}
public class AppStore implements Software{
@Override
public void run() {
System.out.println("app start run");
}
}
public class Camera implements Software{
@Override
public void run() {
System.out.println("Camera start run");
}
}
继承是一种强耦合,通过桥接把他们关联起来,如同弱耦合,从这里可以看出聚合是一种比继承要弱的关系,两个都可以独立进行变化,不会相互影响。
当两个类存在独立的变化维度,且两个类都需要独立扩展的时候。
组合模式
又叫做部分-整体模式,将对象组合成树状的层次结构模式,表示部分-整体的关系,使用户对单个对象和组合对象具有一定访问一致性。
模糊了简单元素与复杂元素的概念,客户端可以处理简单元素一样来处理复杂元素,从而使客户程序与复杂元素内部解耦。
缺点就是客户端需要花费更多的时间来处理层次关系。
享元模式
通过共享的方式高效的支持大量细颗粒对象。
当有大对象的时候,可能会造成内存溢出,我们把其中共同部分抽象出来,如果有相同的业务请求,直接返回内存已有对象。
用唯一标识码,如果在内存中有,则返回唯一标识码标识的对象。hashmap,java中的String如果有则返回,没有则创建一个字符串保存在字符串缓存池中