结构型模式主要是描述如何将类和对象按某种布局组成更大的结构。可以分为类结构型模式和对象结构型模式。
结构型模式:
将某个类的接口转化为客户端期望的另外一个接口。解决兼容性问题,让原本因接口不匹配不能一起工作的两个类可以协同工作。该模式主要分为类结构模型和对象结构型模式,类结构模式耦合性会比较高。如之前所说。组合优于继承。
优点:
缺点:
应用场景
类适配器UML:
适配者代码如下,返回的是Integer
public class Adaptee {
public Integer specificRequest(){
return 1;
}
}
适配器接口以及适配器
public interface Target {
String request();
}
public class ClassAdapter extends Adaptee implements Target {
@Override
public String request() {
Integer value = specificRequest();
return String.valueOf(value);
}
}
测试
public class Client {
public static void main(String[] args) {
Target target = new ClassAdapter();
String request = target.request();
System.out.println(request); // 1
}
}
对象适配器UML:
适配者如下,接口不同,返回的数据是String
public class Adaptee {
String specificRequest(){
return "2";
}
}
适配器如下
public interface Target {
Integer request();
}
public class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee){
this.adaptee = adaptee;
}
@Override
public Integer request() {
String value = adaptee.specificRequest();
return Integer.valueOf(value);
}
}
调用者
public class Client {
public static void main(String[] args) {
Target target = new ObjectAdapter(new Adaptee());
Integer value = target.request();
System.out.println(value);
}
}
小结:
适配器模式使用场景应当是现存接口仍在正常使用,或者业务逻辑复杂暂时无法明确,可以通过适配器进行适配接口。
桥接模式就是将实现与抽象放在两个不同类层次中,基于最小设计原则,用过封装,聚合及继承等行为让不同的类承担不同职责。总之,就是将抽象与行为实现分离,保证各部分独立性以及功能扩展
优点:
缺点:
应用场景:
角色
代码实现
实现化
public interface Implementor { void operationImpl(); } public class ConcreteImplementorA implements Implementor { @Override public void operationImpl() { System.out.println("ConcreteImplementorA"); } } public class ConcreteImplementorB implements Implementor { @Override public void operationImpl() { System.out.println("ConcreteImplementorB"); } }
抽象化
public abstract class Abstraction { protected Implementor implementor; protected Abstraction(Implementor implementor){ this.implementor = implementor; } public abstract void operation(); } // 根据业务场景,如果有多个,可以构造多个扩展抽象化角色 public class RefinedAbstraction extends Abstraction { protected RefinedAbstraction(Implementor implementor) { super(implementor); } @Override public void operation() { System.out.println("RefinedAbstraction, if there needs, the could be more RefinedAbstraction"); implementor.operationImpl(); } }
调用
public class Client { public static void main(String[] args) { Implementor implementorA = new ConcreteImplementorA(); Implementor implementorB = new ConcreteImplementorB(); RefinedAbstraction abstractionA = new RefinedAbstraction(implementorA); RefinedAbstraction abstractionB = new RefinedAbstraction(implementorB); abstractionA.operation(); System.out.println("---------"); abstractionB.operation(); /** * RefinedAbstraction, if there needs, the could be more RefinedAbstraction * ConcreteImplementorA * --------- * RefinedAbstraction, if there needs, the could be more RefinedAbstraction * ConcreteImplementorB */ } }
小结:
桥接模式常见的使用场景就是替换多层继承,可以减少子类的个数,降低系统的管理和维护成本,继承确实有较多优点,继承可以很好实现代码复用的功能,但是这个封装特性也是继承的缺点,因为子类会继承父类所有的方法,根据合成复用原则,优先使用组合或者聚合。
在不改变现有对象结构情况下,动态给对象增加职责。举个例子,对于登陆展示功能,要求增加一个一句欢迎的话语,并且要求不能修改原有接口,这个时候就可以使用装饰模式
优点:
缺点:
装饰模式UML
代码如下:
首先定义接口以及具体构件(构件也可以投多种实现)
public interface Component { void operation(); } public class ConcreteComponent implements Component { @Override public void operation() { System.out.println("i am concrete component"); } }
装饰:
public abstract class Decorator implements Component { protected Component component; public Decorator(Component component){ this.component = component; } public abstract void operation(); } public class ConcreteDecorateA extends Decorator { public ConcreteDecorateA(Component component) { super(component); } @Override public void operation() { component.operation(); this.addFunction(); } private void addFunction() { System.out.println("add function in concrete decorate A"); } } public class ConcreteDecorateB extends Decorator { public ConcreteDecorateB(Component component) { super(component); } @Override public void operation() { this.addFunction(); component.operation(); } private void addFunction() { System.out.println("this add function in concrete decorator B"); } }
实现:
public class Client { public static void main(String[] args) { Component component = new ConcreteComponent(); Component decorateA = new ConcreteDecorateA(component); Component decorateB = new ConcreteDecorateB(decorateA); decorateB.operation(); /** * this add function in concrete decorator B * i am concrete component * add function in concrete decorate A */ } }
又称整体-部分(Part-Whole)模式,将对象组合成树状的层次接口的模式。用以表示“整体-部分”关系,是客户端对单个对象以及组合队形具有一致的访问性
优点:
缺点:
适用场景:
组合模式UML:
代码如下:
构件接口
public interface Component { void add(Component component); void remove(Component component); Component getChild(int t); void operation(); }
树枝构件
public class Composite implements Component { private String name; private List<Component> children = new ArrayList<>(); public Composite(String name){ this.name = name; } @Override public void add(Component component) { children.add(component); } @Override public void remove(Component component) { children.remove(component); } @Override public Component getChild(int t) { if (children.size() > t) return children.get(t); return null; } @Override public void operation() { System.out.println("this is composite, name : " + this.name); for (Component child : children) { child.operation(); } } }
树叶构件
public class Leaf implements Component { String name; public Leaf(String name) { this.name = name; } @Override public void add(Component component) { throw new RuntimeException(); } @Override public void remove(Component component) { throw new RuntimeException(); } @Override public Component getChild(int t) { throw new RuntimeException(); } @Override public void operation() { System.out.println("this is leaf, name: " + this.name); } }
客户端
public class Client { public static void main(String[] args) { Leaf leafA = new Leaf("leafA"); Leaf leafB = new Leaf("leafB"); Composite compositeA = new Composite("compositeA"); Composite compositeB = new Composite("compositeB"); compositeA.add(leafA); compositeB.add(leafB); Composite compositeC = new Composite("compositeC"); compositeC.add(compositeA); compositeC.add(compositeB); compositeC.operation(); /** * this is composite, name : compositeC * this is composite, name : compositeA * this is leaf, name: leafA * this is composite, name : compositeB * this is leaf, name: leafB */ } }
小结:
组合模式组号保证树叶构件与树枝构件有较好的抽象性,否则会增加较多冗余方法。
通过为多个复杂的子系统提供一致性访问接口,从而使子系统更容易被访问。举个例子,比如在进行使用阿里云oss时,我们会进行封装将配置信息以及调用分别进行封装,最终暴露给业务端使用的就是一个简单的接口,业务端很容易调用这个接口进行存储。
优点:
缺点:
适用场景:
外观模式UML:
代码:
public class SubSystem1 { public void method1(){ System.out.println("SubSystem1"); } } public class SubSystem2 { public void method2(){ System.out.println("SubSystem2"); } } public class SubSystem3 { public void method3(){ System.out.println("SubSystem3"); } } public class Facade { private SubSystem1 subSystem1 = new SubSystem1(); private SubSystem2 subSystem2 = new SubSystem2(); private SubSystem3 subSystem3 = new SubSystem3(); public void method() { subSystem1.method1(); subSystem2.method2(); subSystem3.method3(); } } public class Client { public static void main(String[] args) { Facade facade = new Facade(); facade.method(); /** * SubSystem1 * SubSystem2 * SubSystem3 */ } }
小结:
外观模式通过定义一个一致接口,用以屏蔽内部子系统的细节,是的调用端只需要跟这个接口发生调用,无需关心内部细节。使用外观模式可以帮助客户端与子系统进行解耦,是的子系统内部模块更以维护以及扩展。合理使用外观模式,可以帮助我们更好的划分访问的层次。如果子系统很简单,就不要过多使用外观模式,增加温乎成本。所有的思想都是系统有层次,利于维护。
又称蝇量模式,就是运用共享技术邮箱的支持大量细粒度的对象。也就是共享一寸的对象来减少需要创建的对象数量,避免大量相似的开销,从而提升资源的利用率
优点:
缺点:
适用场景:
享元模式的UML:
各角色定义:
代码如下:
抽象享元角色:
public interface Flyweight { void operation(UnsharedConcreteFlyweight state); }
具体享元角色:
public class ConcreteFlyweight1 implements Flyweight { public String key; public ConcreteFlyweight1(String key) { System.out.println("create ConcreteFlyweight1: " + key); this.key = key; } @Override public void operation(UnsharedConcreteFlyweight state) { System.out.println("ConcreteFlyweight1 has been used: " + key); System.out.println("unShared is: " + (Objects.nonNull(state) ? state.getInfo() : "nothing")); } } public class ConcreteFlyweight2 implements Flyweight { public String key; public ConcreteFlyweight2(String key) { System.out.println("create ConcreteFlyweight2: " + key); this.key = key; } @Override public void operation(UnsharedConcreteFlyweight state) { System.out.println("ConcreteFlyweight2 has been used: " + key); System.out.println("unShared is: " + (Objects.nonNull(state) ? state.getInfo() : "nothing")); } }
非共享享元角色:
public class UnsharedConcreteFlyweight { private String info; public UnsharedConcreteFlyweight(String info) { this.info = info; } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
享元工厂角色:
public class FlyweightFactory { private final Map<String, Flyweight> flyweights = new HashMap<>(); private int count = 0; public Flyweight getFlyweight(String key) { if (!flyweights.containsKey(key)) { synchronized (this) { if (!flyweights.containsKey(key)) { // 这里取决于业务场景 flyweights.put(key, count % 2 == 1 ? new ConcreteFlyweight1(key) : new ConcreteFlyweight2(key)); count++; } } } return flyweights.get(key); } }
客户端:
public class Client { public static void main(String[] args) { FlyweightFactory factory = new FlyweightFactory(); Flyweight a01 = factory.getFlyweight("a"); Flyweight a02 = factory.getFlyweight("a"); Flyweight b01 = factory.getFlyweight("b"); Flyweight b02 = factory.getFlyweight("b"); Flyweight c01 = factory.getFlyweight("c"); Flyweight c02 = factory.getFlyweight("c"); a01.operation(new UnsharedConcreteFlyweight("first")); a02.operation(new UnsharedConcreteFlyweight("second")); b01.operation(new UnsharedConcreteFlyweight("first")); b02.operation(new UnsharedConcreteFlyweight("second")); c01.operation(new UnsharedConcreteFlyweight("first")); c02.operation(new UnsharedConcreteFlyweight("second")); /** * create ConcreteFlyweight2: a * create ConcreteFlyweight1: b * create ConcreteFlyweight2: c * ConcreteFlyweight2 has been used: a * unShared is: first * ConcreteFlyweight2 has been used: a * unShared is: second * ConcreteFlyweight1 has been used: b * unShared is: first * ConcreteFlyweight1 has been used: b * unShared is: second * ConcreteFlyweight2 has been used: c * unShared is: first * ConcreteFlyweight2 has been used: c * unShared is: second */ } }
小结:
享元工厂也可以认为是工厂模式的扩展类,将相当于在中间加了一层缓冲。使用享元模式,最好是系统中存在大量的相似对象或频繁使用对象。否则没有必要。
享元模式提高了系统的复杂度,需要分离内部状态以及外部状态,外部状态具有固化属性,不应岁内部章台变化而变化
为一个对象提供一个替身,以便控制这个对象的访问。通过代理对象访问目标对象。
优点:
缺点:
应用场景:
代理模式的UML:
代码如下,代理模式比较简单:
public interface Subject { void request(); } public class RealSubject implements Subject { @Override public void request() { System.out.println("real request"); } } public class Proxy implements Subject { private final RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void request() { this.preRequest(); this.realSubject.request(); this.postRequest(); } private void preRequest() { System.out.println("pre request"); } private void postRequest() { System.out.println("post request"); } } public class Client { public static void main(String[] args) { Proxy proxy = new Proxy(new RealSubject()); proxy.request(); /** * pre request * real request * post request */ } }
上述属于静态代理,静态代理有一个缺点:
代理对象需要跟目标对象实现一样的接口,并且一旦接口增加方法,目标对象与代理对象都要维护
学过java都知道还有一个动态代理(接口代理)以及cglib代理,这个代理对象不需要实现接口,维护以及扩展都比较方便
看一下动态代理的反射以及客户端调用
public class ProxyFactory { private Object target; public ProxyFactory(Object target) { this.target = target; } public Object getInstant(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> { System.out.println("pre request"); Object invoke = method.invoke(target, args); System.out.println("post request"); return invoke; }); } } public class Client { public static void main(String[] args) { DynamicSubject dynamicRealSubject = new DynamicRealSubject(); ProxyFactory proxyFactory = new ProxyFactory(dynamicRealSubject); DynamicSubject dynamicSubject = (DynamicSubject) proxyFactory.getInstant(); dynamicSubject.request(); /** * pre request * real request * post request */ } }
使用动态代理必须实现接口,对于没有接口的需要使用cglib进行代理
cglib代理也叫做子类代理,他是在内存中构建一个子类对象从事实现对目标对象的动态代理,注意类不能是final,否则会报错,因为无法继承,目标方法不能是final或者static,否则不会执行目标独享额外的方法
被代理对象
public class CglibObject { public void request() { System.out.println("i am real object"); } }
代理类
public class ProxyFactory implements MethodInterceptor { private final Object target; public ProxyFactory(Object target) { this.target = target; } public Object getInstance() { // 创建一个工具类 Enhancer enhancer = new Enhancer(); // 设置父类 enhancer.setSuperclass(target.getClass()); // 设置回调函数 enhancer.setCallback(this); // 返回子类对象,即代理对象 return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("pre request"); Object invoke = method.invoke(target, args); System.out.println("post request"); return invoke; } }
客户端
public class Client { public static void main(String[] args) { CglibObject cglibObject = new CglibObject(); ProxyFactory proxyFactory = new ProxyFactory(cglibObject); CglibObject instance = (CglibObject) proxyFactory.getInstance(); instance.request(); /** * pre request * i am real object * post request */ } }
小结:
通过代理模式访问目标对象,这样足以哦可以再目标对象实现的基础上,额外增强功能,并且实现一定程度的接口,但是也会造成额外的开销。
原文:https://www.cnblogs.com/yangshixiong/p/14056533.html