结构型模式
前面创建型模式介绍了创建对象的一些设计模式,这节介绍的结构型模式旨在通过改变代码结构来达到解耦的目的,使得我们的代码容易维护和扩展。
1.组合模式
组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
角色:
Composite:组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component的子部件。
Leaf:叶子节点,在组合中表示叶节点对象,叶节点没有子节点。
Composite:定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关的操作。
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract void add(Component c);
public abstract void Remove(Component c);
public abstract void Display(int depth);
}
......................
public class Composite extends Component {
private List<Component> children = new ArrayList<Component>();
public Composite(String name) {
super(name);
}
@Override
public void add(Component c) {
children.add(c);
}
@Override
public void Remove(Component c) {
children.remove(c);
}
@Override
public void Display(int depth) {
for(Component c:children) {
c.Display(depth++);
}
}
}
......................
public class Leaf extends Component{
public Leaf(String name) {
super(name);
}
@Override
public void add(Component c) {
}
@Override
public void Remove(Component c) {
}
@Override
public void Display(int depth) {
System.out.println(new String("-")+name);
}
}
....................
public class Test {
public static void main(String[] args) {
Composite root = new Composite("树根节点");
root.add(new Leaf("叶子节点A"));
root.add(new Leaf("叶子节点B"));
Composite subroot = new Composite("分支节点");
subroot.add(new Leaf("叶子节点X"));
subroot.add(new Leaf("叶子节点Y"));
root.add(subroot);
Composite subroot2 = new Composite("分支节点2");
subroot2.add(new Leaf("叶子节点m"));
subroot2.add(new Leaf("叶子节点n"));
subroot.add(subroot2);
root.Display(1);
}
}
何时用组合模式?
当你发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象时,就应该考虑用组合模式了。
2.适配器模式
适配器模式,将一个类的接口转换成客户希望的另外一个接口,。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
角色:
Target:这是客户期待的接口。目标可以是具体或抽象的类,也可以是接口
Adapter:通过在内部包装一个Adaptee对象,把源接口转换成目标接口
Adaptee:需要适配的类
public class Target {
public void request() {
System.out.println("普通请求!");
}
}
-----
public class Adaptee {
public void specificRequest() {
System.out.println("特殊请求!");
}
}
-----
public class Adapter extends Target{
private Adaptee adaptee = new Adaptee();
public void request() {
adaptee.specificRequest();
}
}
-----
public class Test {
public static void main(String[] args) {
Target t = new Adapter();
t.request();
}
}
何时使用适配器模式?
两个类所做的事情相同或相似,但是具有不同的接口时要使用它。
3.桥接模式
桥接模式,将抽象部分与它的实现部分分离,使它们都可以独立的变化。
角色:
抽象
具体抽象实现
抽象实现
具体实现
桥接模式,我的理解就是系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让他们独立变化,减少它们之间的耦合性。
public abstract class Implementor {
public abstract void operation();
}
---
public class ConcreteImplementorA extends Implementor{
@Override
public void operation() {
System.out.println("执行A方法");
}
}
-----
public class ConcreteImplementorB extends Implementor{
@Override
public void operation() {
System.out.println("执行A方法");
}
}
-----
public class Abstraction {
protected Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
public void operation() {
implementor.operation();
}
}
-----
public class RefinedAbstraction extends Abstraction{
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
public void operation() {
implementor.operation();
}
}
-----
public class Test {
public static void main(String[] args) {
Implementor imp = new ConcreteImplementorA();
Abstraction ab = new RefinedAbstraction(imp);
ab.operation();
}
}
4.装饰模式
装饰模式,动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
角色:
Component:定义一个对象接口,可以给这些对象动态的添加职责。
Decorator:装饰抽象类,继承Component,从外类扩展Component类的功能,对于Component来说,是无需知道Decorator存在的。
ConcreteDecorator:具体装饰类,起到给Component添加职责的功能。
ConcreteComponent :定义了具体的对象,也可以给这些对象添加一些职责
public abstract class Component {
public abstract void operation();
}
----
public class ConcreteComponent extends Component{
@Override
public void operation() {
System.out.println("具体对象的操作");
}
}
-----
public abstract class Decorator extends Component{
protected Component component;
public void setComponent(Component component) {
this.component = component;
}
public void operation() {
if(component!=null) {
component.operation();
}
}
}
------
public class ConcreteDecoratorA extends Decorator {
public void operation() {
super.operation();
System.out.println("新功能A");
}
}
------
public class ConcreteDecoratorB extends Decorator{
public void operation() {
super.operation();
System.out.println("新功能B");
}
}
----
public class Test {
public static void main(String[] args) {
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA d1 = new ConcreteDecoratorA();
ConcreteDecoratorB d2 = new ConcreteDecoratorB();
d1.setComponent(c);
d2.setComponent(d1);
d2.operation();
}
}
装饰模式就是用SetComponent来对对象进行包装的,这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。
5.代理模式
代理模式,为其它对象提供一种代理以控制对这个对象的访问。
角色:
Subject:定义了RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy
RealSubject:定义了Proxy所代表的真实实体
Proxy类,保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这样代理就可以用来代替实体。
public abstract class Subject {
public abstract void request();
}
---
public class RealSubject extends Subject{
@Override
public void request() {
System.out.println("真实的请求");
}
}
---
public class Proxy extends Subject{
Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
subject.request();
}
}
----
public class Test {
public static void main(String[] args) {
Subject sub = new RealSubject();
Proxy proxy = new Proxy(sub);
proxy.request();
}
}
6.外观模式
外观模式,为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
角色:
Facade:外观类,知道哪些子系统类负责处理请求,将客户的请求代理给适当的子系统对象。
SubSystemOne:
SubSystemTwo:
SubSystemThree:
…
子系统集合,实现子系统的功能,处理Facade对象指派的任务。注意子类中没有Facade的任何信息,即没有对Facade对象的引用。
public class SubSystemOne {
public void MethodOne() {
System.out.println("方法1");
}
}
-----
public class SubSystemTwo {
public void MethodTwo() {
System.out.println("方法2");
}
}
---
public class SubSystemThree {
public void MethodThree() {
System.out.println("方法3");
}
}
----
public class SubSystemFour {
public void MethodFour() {
System.out.println("方法4");
}
}
-----
//外观类,需要了解所有子系统的方法与属性,进行组合以备外界调用
public class Facade {
SubSystemOne one;
SubSystemTwo two;
SubSystemThree three;
SubSystemFour four;
public Facade() {
one = new SubSystemOne();
two = new SubSystemTwo();
three = new SubSystemThree();
four = new SubSystemFour();
}
public void MethodA() {
System.out.println("方法组A");
one.MethodOne();
two.MethodTwo();
}
public void MethodB() {
System.out.println("方法组B");
three.MethodThree();
four.MethodFour();
}
}
------
public class Test {
public static void main(String[] args) {
Facade f = new Facade();
f.MethodA();
f.MethodB();
}
}
何时使用外观模式?
首先,在设计初期阶段,应该要有意识的将不同的两个层分离,其次,在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,你可以为新系统开发一个外观Facade类,来提供设计粗糙与高度复杂的遗留代码的比较清晰的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。
7.享元模式
享元模式,运用共享技术有效地支持大量细粒度的对象。
角色:
FlyweightFacory:一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)
Flyweight:所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
ConcreteFlyweight:继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间。
UnsharedConcreteFlyweight:指那些不需要共享的Flyweight子类。因为FlyWight接口共享成为可能,但它并不强制共享。
public abstract class Flyweight {
public abstract void operation(int extrinsicstate);
}
----
public class ConcreteFlyweight extends Flyweight {
@Override
public void operation(int extrinsicstate) {
System.out.println("具体Flyweight"+extrinsicstate);
}
}
----
public class UnsharedConcreteFlyweight extends Flyweight{
@Override
public void operation(int extrinsicstate) {
System.out.println("不共享的flyweight"+extrinsicstate);
}
}
----
public class FlyweightFactory {
private HashMap flyweights = new HashMap();
public FlyweightFactory() {
flyweights.put("x",new ConcreteFlyweight());
flyweights.put("y",new ConcreteFlyweight());
flyweights.put("z",new ConcreteFlyweight());
}
//根据客户端请求,获得已生成的实例
public Flyweight getFlyweight(String key) {
return (Flyweight)flyweights.get(key);
}
}
-----
public class Test {
public static void main(String[] args) {
int extrinsicstate = 22;
FlyweightFactory f = new FlyweightFactory();
Flyweight fx = f.getFlyweight("x");
fx.operation(extrinsicstate);
Flyweight fx2 = f.getFlyweight("y");
fx2.operation(extrinsicstate);
Flyweight fx3 = f.getFlyweight("z");
fx3.operation(extrinsicstate);
Flyweight uf = new UnsharedConcreteFlyweight();
uf.operation(extrinsicstate);
}
}
享元模式的应用:
如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。