Java23种设计模式/GOF设计模式--结构型型模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/flyfeifei66/article/details/82529570

目录

结构型模式

6、适配器模式(Adapter pattern)

7、代理模式(Proxy pattern)

8、装饰模式(Decorator pattern)

9、外观模式/门面模式(Facade pattern)

10、桥接模式(Bridge pattern)

11、组合模式/合成模式(Composite pattern)

12、享元模式(Flyweight pattern)


创建型模式

结构型模式

行为型模式


结构型模式


6适配器模式(Adapter pattern)


适配器模式(英语:adapter pattern)有时候也称包装样式或者包装(wrapper)。将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类能在一起工作,做法是将类自己的接口包裹在一个已存在的类中。

  • 类的适配器

通过继承类、实现目标接口实现。

UML

 

  • 对象的适配器

通过持有对象、实现目标接口实现。

UML

 

代码举例

public class AdapteeToClientAdapter implements Adapter {

    private final Adaptee instance;

    public AdapteeToClientAdapter(final Adaptee instance) {

         this.instance = instance;
    }

    @Override
    public void clientMethod() {

       // call Adaptee's method(s) to implement Client's clientMethod
    }
}
  • 接口的适配器

通过一个抽象类屏蔽不需要的接口实现。

7、代理模式(Proxy pattern)


与适配器结构类似,都是wrapper,代理类实现与被代理类同一接口(cgblib下为其子类),适配器模式适配成另一个接口。两者的目的和出发点不同,一个是为了适配成另一个接口,一个是为了“增强”,参考AOP。

proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes. Use of the proxy can simply be forwarding to the real object, or can provide additional logic. In the proxy, extra functionality can be provided, for example caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked. For the client, usage of a proxy object is similar to using the real object, because both implement the same interface.

代理解决了什么问题?

  • 一个类的访问应该被管理和控制
  • 在访问一个类时需要添加额外的功能(AOP)

可能的应用场景

  • 远程代理

In distributed object communication, a local object represents a remote object (one that belongs to a different address space). The local object is a proxy for the remote object, and method invocation on the local object results in remote method invocation on the remote object. An example would be an ATM implementation, where the ATM might hold proxy objects for bank information that exists in the remote server.

  • 虚拟代理

In place of a complex or heavy object, a skeleton representation may be advantageous in some cases. When an underlying image is huge in size, it may be represented using a virtual proxy object, loading the real object on demand.

  • 保护代理

A protection proxy might be used to control access to a resource based on access rights.

UML

代码举例 以下示例解释"虚拟代理"模式。ProxyImage 类别用来访问远程方法。

interface Image {
    public void displayImage();
}

// On System A
class RealImage implements Image {

    private String filename = null;
    /**
     * Constructor
     * @param filename
     */
    public RealImage(final String filename) {
        this.filename = filename;
        loadImageFromDisk();
    }

    /**
     * Loads the image from the disk
     */
    private void loadImageFromDisk() {
        System.out.println("Loading   " + filename);
    }

    /**
     * Displays the image
     */
    public void displayImage() {
        System.out.println("Displaying " + filename);
    }

}

// On System B
class ProxyImage implements Image {

    private RealImage image = null;
    private String filename = null;
    /**
     * Constructor
     * @param filename
     */
    public ProxyImage(final String filename) {
        this.filename = filename;
    }

    /**
     * Displays the image
     */
    public void displayImage() {
        if (image == null) {
           image = new RealImage(filename);
        }
        image.displayImage();
    }

}

class ProxyExample {

   /**
    * Test method
    */
   public static void main(final String[] arguments) {
        final Image image1 = new ProxyImage("HiRes_10MB_Photo1");
        final Image image2 = new ProxyImage("HiRes_10MB_Photo2");

        image1.displayImage(); // loading necessary
        image1.displayImage(); // loading unnecessary
        image2.displayImage(); // loading necessary
        image2.displayImage(); // loading unnecessary
        image1.displayImage(); // loading unnecessary
    }
}

8、装饰模式(Decorator pattern)


通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。

修饰模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰模式是在运行时增加行为。

当有几个相互独立的功能需要扩充时,这个区别就变得很重要。在有些面向对象的编程语言中,类不能在运行时被创建,通常在设计的时候也不能预测到有哪几种功能组合。这就意味着要为每一种组合创建一个新类。相反,修饰模式是面向运行时候的对象实例的,这样就可以在运行时根据需要进行组合。

装饰者模式解决了什么问题?

  • Responsibilities should be added to (and removed from) an object dynamically at run-time.
  • A flexible alternative to subclassing for extending functionality should be provided.

When using subclassing, different subclasses extend a class in different ways. But an extension is bound to the class at compile-time and can't be changed at run-time.

UML

需要运行期间为对象添加功能,或者要为子类灵活添加功能时可以使用装饰模式,不是装饰模式要么无法实现,要么实现起来太复杂。例如:

一个窗口系统中的窗口,允许这个窗口内容滚动,我们希望给它添加水平或垂直滚动条。假设窗口通过“Window”类实例来表示,并且假设它没有添加滚动条功能。

我们可以创建一个子类“ScrollingWindow”来提供, 假设现在我们希望给我们的窗口添加边框,同样,我们的原始Window类不支持、ScrollingWindow子类也不支持,如果我们想要给所有窗口添加边框,我们必须创建WindowWithBorderScrollingWindowWithBorder子类。显然,这个问题由于被添加类而变得更糟了。简单的来说,一个类在初期设计好之后,后期想要拓展,我们优先使用合成/复用(Composite Reuse Principle原则),而不是继承,继承会导致类爆炸。

对于修饰模式,我们简单的创建一个新类BorderedWindowDecorator,在运行时,我们能够使用ScrollingWindowDecoratorBorderedWindowDecorator或两者结合来修饰已存在的窗口。 

使用装饰模式解决问题UML

代码举例

这个JAVA示例使用window/scrolling情境。

// The Window interface class
public interface Window {
	public void draw(); // Draws the Window
	public String getDescription(); // Returns a description of the Window
}


// implementation of a simple Window without any scrollbars
public class SimpleWindow implements Window {
	public void draw() {
		// Draw window
	}

	public String getDescription() {
		return "simple window";
	}
}
以下类包含所有Window类的decorator,以及修饰类本身。

// abstract decorator class - note that it implements Window
public abstract class WindowDecorator implements Window {
    protected Window decoratedWindow; // the Window being decorated

    public WindowDecorator (Window decoratedWindow) {
        this.decoratedWindow = decoratedWindow;
    }
    
    @Override
    public void draw() {
        decoratedWindow.draw();
    }

    @Override
    public String getDescription() {
        return decoratedWindow.getDescription();
    }
}


// The first concrete decorator which adds vertical scrollbar functionality
public class VerticalScrollBar extends WindowDecorator {
	public VerticalScrollBar(Window windowToBeDecorated) {
		super(windowToBeDecorated);
	}

	@Override
	public void draw() {
		super.draw();
		drawVerticalScrollBar();
	}

	private void drawVerticalScrollBar() {
		// Draw the vertical scrollbar
	}

	@Override
	public String getDescription() {
		return super.getDescription() + ", including vertical scrollbars";
	}
}


// The second concrete decorator which adds horizontal scrollbar functionality
public class HorizontalScrollBar extends WindowDecorator1 {
	public HorizontalScrollBar (Window windowToBeDecorated) {
		super(windowToBeDecorated);
	}

	@Override
	public void draw() {
		super.draw();
		drawHorizontalScrollBar();
	}

	private void drawHorizontalScrollBar() {
		// Draw the horizontal scrollbar
	}

	@Override
	public String getDescription() {
		return super.getDescription() + ", including horizontal scrollbars";
	}
}
以下是一个测试程序,它创建了一个包含多重装饰的Window实例(如,包含了垂直的和水平的滚动条),然后输出它的描述:

public class Main {
	// for print descriptions of the window subclasses
	static void printInfo(Window w) {
		System.out.println("description:"+w.getDescription());
	}
	public static void main(String[] args) {
		// original SimpleWindow
		SimpleWindow sw = new SimpleWindow();
		printInfo(sw);
		// HorizontalScrollBar  mixed Window
		HorizontalScrollBar hbw = new HorizontalScrollBar(sw);
		printInfo(hbw);
		// VerticalScrollBar mixed Window
		VerticalScrollBar vbw = new VerticalScrollBar(hbw);
		printInfo(vbw);
	}
}

以下是SimpleWindow及添加了组件HorizontalScrollBar和VerticalScrollBar后的Window测试结果:

description:simple window

description:simple window, including horizontal scrollbars

description:simple window, including horizontal scrollbars, including vertical scrollbars

9外观模式/门面模式(Facade pattern)


外观模式(Facade pattern),是软件工程中常用的一种软件设计模式,它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。

What problems can the Facade design pattern solve? 

  • To make a complex subsystem easier to use, a simple interface should be provided for a set of interfaces in the subsystem.
  • The dependencies on a subsystem should be minimized.

Clients that access a complex subsystem directly refer to (depend on) many different objects having different interfaces (tight coupling), which makes the clients hard to implement, change, test, and reuse.

UML

 

代码举例(电脑开机,包含很多个步骤,你只需要按下开机键)

/* Complex parts */

class CPU {
    public void freeze() { ... }
    public void jump(long position) { ... }
    public void execute() { ... }
}

class HardDrive {
    public byte[] read(long lba, int size) { ... }
}

class Memory {
    public void load(long position, byte[] data) { ... }
}

/* Facade */

class ComputerFacade {
    private CPU processor;
    private Memory ram;
    private HardDrive hd;

    public ComputerFacade() {
        this.processor = new CPU();
        this.ram = new Memory();
        this.hd = new HardDrive();
    }

    public void start() {
        processor.freeze();
        ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE));
        processor.jump(BOOT_ADDRESS);
        processor.execute();
    }
}

/* Client */

class You {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start();
    }
}

10、桥接模式(Bridge pattern)


桥接模式是软件设计模式中最复杂的模式之一,它把事物对象和其具体行为、具体特征分离开来,使它们可以各自独立的变化。(正常情况下面向对象中的类是特性和行为的集合,这里就分开了)

桥接模式解决了什么问题? 

  • An abstraction and its implementation should be defined and extended independently from each other.
  • A compile-time binding between an abstraction and its implementation should be avoided so that an implementation can be selected at run-time.

When using subclassing, different subclasses implement an abstract class in different ways. But an implementation is bound to the abstraction at compile-time and can't be changed at run-time.

事物对象仅是一个抽象的概念。如“圆形”、“三角形”归于抽象的“形状”之下,而“画圆”、“画三角”归于实现行为的“画图”类之下,然后由“形状”调用“画图”。

​UML

  • Abstraction

定义抽象的接口

该接口包含实现具体行为、具体特征的Implementor接口

  • Refined Abstraction

抽象接口Abstraction的子类,依旧是一个抽象的事物名

  • Implementor

定义具体行为、具体特征的应用接口

  • ConcreteImplementor

实现Implementor接口

代码举例 (bridge中的shape和drawing都是可以变化的,统一在桥中相遇)

/** "Implementor" */
interface DrawingAPI
{
    public void drawCircle(double x, double y, double radius);
}

/** "ConcreteImplementor" 1/2 */
class DrawingAPI1 implements DrawingAPI
{
   public void drawCircle(double x, double y, double radius) 
   {
        System.out.printf("API1.circle at %f:%f radius %f\n", x, y, radius);
   }
}

/** "ConcreteImplementor" 2/2 */
class DrawingAPI2 implements DrawingAPI
{
   public void drawCircle(double x, double y, double radius) 
   { 
        System.out.printf("API2.circle at %f:%f radius %f\n", x, y, radius);
   }
}

/** "Abstraction" */
interface Shape
{
   public void draw();                                            // low-level
   public void resizeByPercentage(double pct);     // high-level
}

/** "Refined Abstraction" */
class CircleShape implements Shape
{
   private double x, y, radius;
   private DrawingAPI drawingAPI;
   public CircleShape(double x, double y, double radius, DrawingAPI drawingAPI)
   {
       this.x = x;  this.y = y;  this.radius = radius; 
       this.drawingAPI = drawingAPI;
   }

   // low-level i.e. Implementation specific
   public void draw()
   {
        drawingAPI.drawCircle(x, y, radius);
   }   
   // high-level i.e. Abstraction specific
   public void resizeByPercentage(double pct)
   {
        radius *= pct;
   }
}

/** "Client" */
class BridgePattern {
   public static void main(String[] args)
   {
       Shape[] shapes = new Shape[2];
       shapes[0] = new CircleShape(1, 2, 3, new DrawingAPI1());
       shapes[1] = new CircleShape(5, 7, 11, new DrawingAPI2());

       for (Shape shape : shapes)
       {
           shape.resizeByPercentage(2.5);
           shape.draw();
       }
   }
}

 JDBC访问数据也是典型的桥的使用,不同的驱动代表不同的行为实现(对应我们上述例子的“draw”动作),不同的数据库(虽然已不是代码的一部分,对应我们上述例子的shape)是不同的事物。

11组合模式/合成模式(Composite pattern)

将有整体-部分的结构的每个组件统一结构化,典型的代表就是处理“树”。树中每个节点都是“一样的”Node,他们通过父节点、子节点构成层级结构,由于他们是同一类型,能大大简化实现逻辑,同时有着无限的拓展能力。

In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes a group of objects that is treated the same way as a single instance of the same type of object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly。

Composite design pattern 解决了什么问题?

  • A part-whole hierarchy should be represented so that clients can treat part and whole objects uniformly.
  • A part-whole hierarchy should be represented as tree structure.

UML

代码举例

/** "Component" */
interface Graphic {

    //Prints the graphic.
    public void print();
}

/** "Composite" */
class CompositeGraphic implements Graphic {

    //Collection of child graphics.
    private List<Graphic> childGraphics = new ArrayList<Graphic>();

    //Prints the graphic.
    public void print() {
        for (Graphic graphic : childGraphics) {
            graphic.print();  //Delegation
        }
    }

    //Adds the graphic to the composition.
    public void add(Graphic graphic) {
        childGraphics.add(graphic);
    }

    //Removes the graphic from the composition.
    public void remove(Graphic graphic) {
        childGraphics.remove(graphic);
    }
}

/** "Leaf" */
class Ellipse implements Graphic {

    //Prints the graphic.
    public void print() {
        System.out.println("Ellipse");
    }
}

/** Client */
public class Program {

    public static void main(String[] args) {
        //Initialize four ellipses
        Ellipse ellipse1 = new Ellipse();
        Ellipse ellipse2 = new Ellipse();
        Ellipse ellipse3 = new Ellipse();
        Ellipse ellipse4 = new Ellipse();

        //Initialize three composite graphics
        CompositeGraphic graphic = new CompositeGraphic();
        CompositeGraphic graphic1 = new CompositeGraphic();
        CompositeGraphic graphic2 = new CompositeGraphic();

        //Composes the graphics
        graphic1.add(ellipse1);
        graphic1.add(ellipse2);
        graphic1.add(ellipse3);

        graphic2.add(ellipse4);

        graphic.add(graphic1);
        graphic.add(graphic2);

        //Prints the complete graphic (Four times the string "Ellipse").
        graphic.print();
    }
}

12、享元模式(Flyweight pattern)


是池化的思想,将各个无状态的bean用容器(比如map)存放,需要时取出,不用时放回,各个线程共享这些bean。

Flyweight design pattern 解决了什么问题?

  • Large numbers of objects should be supported efficiently.
  • Creating large numbers of objects should be avoided.

UML

猜你喜欢

转载自blog.csdn.net/flyfeifei66/article/details/82529570
今日推荐