java设计模式-结构型模式

结构型模式包括:适配器模式,桥接模式,代理模式,外观模式,装饰模式,组合模式,享元模式。用于构建类间的关系,设计对象的结构、继承和依赖关系。

  • 适配器模式: 将一个类的接口转化成另一个接口,源-适配器-目标,包括类、对象、双向适配器;
  • 桥接模式:分离具体实现和抽象,两个维度的接口,具体实现,分别组合。
  • 代理模式:客户不直接操作业务实体subject,操作业务代理proxy,proxy类中含有对subject的引用,并且调用其操作方法。
  • 外观模式:子系统按顺序完成一些角色,增加一个外观角色,实例化子系统对象并调用这些方法,对客户提供一个简单的接口。
  • 装饰模式:动态地给一个对象添加一些额外的职责,构件和其装饰抽象类都impliment同一个抽象构件角色,装饰类继承这个装饰抽象类,并且重写接口方法,在super之前先做或者后做一些事情。
  • 组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构,它使得客户对单个对象和复合对象的使用具有一致性。公用接口实现所有方法,对某些部分没用的方法使用默认实现,整体重写那些方法。
  • 享元模式:享元模式使用共享技术有效地支持大量的细粒度对象。通过享元工厂来控制多次创建同一个对象。

1.适配器模式Adapter:

将一个类的接口转换成客户希望的另外一个接口。

  • 目标(Target):需要转换成的接口
  • 源(Adaptee):需要转换的接口
  • 适配器(Adapter),用来转换的接口

类适配器:使用继承的方式使用源,新建一个类Adapter,继承原有系统中的Adaptee,再使用此类实现客户接口ITarget。
对象适配器:使用委托的方式使用源。新建一个类Adapter,实现Itarget接口,委托对象,即声明一个Adaptee的源对象,在Adapter的构造方法中传入这个源对象,在目标接口中的方法即可使用Adaptee对象的各种方法。
编程中优先使用对象组合,而不是类继承。
双向适配器:新建一个类Adapter,同时实现了源接口和目标接口,在类中委托源对象adaptee,在构造方法中传入一个源对象,目标接口中的方法可以使用委托对象中的各种方法,源接口中的方法可以直接使用委托对象.func()实现。
代码实现:

public interface IOneAdaptee{
//源所实现的接口
    public void operateA();
    public void operateB();
}
public class OneAdaptee impliment IOneAdaptee{ //一个源
    public void operateA(){}
    public void operateB(){}
}
public interface ITarget{
//目标接口
    public void operateC();
    public void operateD();
}
//类适配器
public class ClassAdapter extends OneAdaptee impliments ITarget{
    //目标接口中的方法
    public void operateC(){//可以调用父类中的方法}
    public void operateD(){}
}
//对象适配器
public class ObjectAdapter impliments ITarget{
    //委托对象
    private IOneAdaptee adaptee;
    //构造方法,传入一个源对象
    public ObjectAdapter(IOneAdaptee oneAdaptee){
     this.adaptee = oneAdaptee;
    }
 //目标接口中的方法
    public void operateC(){//可以调用委托对象的各种方法}
    public void operateD(){}
}
//双向适配器
public class Object2Adapter impliments ITarget,IOneAdaptee{
    //委托对象
    private IOneAdaptee adaptee;
    //构造方法,传入一个源对象
    public ObjectAdapter(IOneAdaptee oneAdaptee){
     this.adaptee = oneAdaptee;
    }
    //目标接口中的方法
    public void operateC(){//可以调用委托对象的各种方法}
    public void operateD(){}
    //源接口中的方法
    public void operateA(){adaptee.operateA();}
    public void operateB(){adaptee.operateB();}
}

2.桥接模式

桥接模式对抽象部分和实现部分进行解耦,当事物有多个维度的变化时,使用该模式来组合。
  1. Abstraction(抽象类):定义抽象部分的接口,维护一个Implementor(实现抽象类)的对象。
  2. RefinedAbstraction(扩充抽象类):扩充由Abstraction定义的接口。
  3. Implementor(实现类接口):提供基本操作。
  4. ConcreteImplementor(具体实现类):实现Implementor的接口并且具体实现它。
  抽象部分和实现部分,各定义一个抽象类,其子类继承并进行具体实现,在使用时,将两个部分进行组合。避免了多继承的关系。
  实现:

//抽象平台
public abstract class ImpLog {
     public abstract void execute(String msg);
}
//java平台实现类
public class JImpLog extends ImpLog {
    public void execute(String msg) {
        System.out.println("JImpLog:"+msg);
    }
}
//net平台实现类
public class NImpLog extends ImpLog {
    public void execute(String msg) {
        System.out.println("NImpLog:"+msg);
    }
}
//桥接抽象类
public abstract class Log {
    public ImpLog implementor;

    public  void write(String log){
        implementor.execute(log);
    }
}
//桥接到java平台实现类
public class TextFileLog extends Log{
    public TextFileLog(JImpLog jImpLog){
        implementor = jImpLog;
    }
    public void write(String log) {
        implementor.execute(log);
    }
}
//桥接到net平台实现类
public class DatabaseLog extends Log {
    public DatabaseLog(NImpLog nImpLog){
        implementor = nImpLog;
    }
    public void write(String log) {
        implementor.execute(log);
    }
}
//测试类:根据使用的具体log来调用具体的平台
public class Client {
    public static void main(String[] args) {
        Log dblog = new DatabaseLog(new NImpLog());
        dblog.write("NET平台下的Database Log");

        Log txtlog = new TextFileLog(new JImpLog());
        txtlog.write("Java平台下的Text File Log");
    }
}

3.代理模式Proxy

由于某种原因不能让客户代码直接调用业务实体时,需要使用代理模式。
  1.Subject接口:定义了RealSubject和Proxy的共用接口,保证在任何使用RealSubject的地方都能使用Proxy.
  2.RealSubject: 定义Proxy可以代表的实体。
  3.Proxy:代理,保存一个RealSubject实体的引用,控制RealSubject的访问,并能创建和销毁它。
  实现

//Subject接口
public interface Subject{
    public void request();
}
//RealSubject实现类
public class RealSubject impliments Subject{
    public RealSubject(){}
    @Override
    public void request(){
        System.out.print("运行业务功能");
    }
}
//Proxy代理类
public class Proxy impliments Subject{
    private Subject realSubject;
    public proxy(){}
    @Override
    public void request(){
    //对象实例化,懒加载,使用时才创建
    if(realSubject == nill){
        realSubject = new RealSubject();
    }
        System.out.print("代理调用业务开始");
        realSubject.request();
        System.out.print("代理调用业务结束");
    }
}
//客户调用
public class Client{
    public static void main(String[] args){
        Subject subject = new Proxy();
        subject.request();
    }
}

4.外观接口Facade

为了给一组子系统提供一个一致的界面,供客户端使用。例如购物助手,可以帮助客户完成下单,选货,发票等业务,而节省客户的操作流程。
  1.外观角色:提供接口或者类,供客户代码调用来使用系统功能。客户与系统之间解耦合。
  2.子系统角色:实现具体功能,在外观角色中创建子系统的引用,并且调用其中的方法。
  实现
  

//子系统A1,A2,A3
class A1 {

    public void doSomething1() {
        //...
    }
}

class A2 {

    public void doSomething2() {
        //...
    }
}

class A3 {

    public void doSomething3() {
        //...
    }
}
//外观角色
public class Facade {

    public void doSomething() {
        A1 a1 = new A1();
        A2 a2 = new A2();
        A3 a3 = new A3();
        a1.doSomething1();
        a2.doSomething2();
        a3.doSomething3();
    }
}

public class Client {

    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.doSomething();
    }
}

5.装饰模式

装饰模式可以动态地给一个对象添加一些额外的职责。
  1.抽象构件角色:定义一个抽象接口,以规范准备接受附加责任的对象。
  2.具体构件角色:这是被装饰者,实现抽象接口,定义一个将要被装饰模式增加功能的类。
  3.装饰角色:装饰器类,抽象类,实现抽象接口,定义一个用于装饰的私有对象,在构造方法中传入装饰对象,实现接口方法。
  4.具体构建角色:继承装饰器类,负责给构件添加增加的功能。在构造方法中传入装饰对象,调用Super(装饰对象)父类的构造方法,重写接口方法,在方法中增加功能,且super.func()调用装饰对象的方法。
  实现

//抽象票据构件:规范要接收附加责任的对象
public interface Component {
    public void printTicket();
}
//具体票据:被装饰者
class SalesTicket impiments Component {
    //实现接口中的方法
    public void printTicket() {
        System.out.println("打印出salesTicket的内容");
    }
}
//发票装饰抽象类
abstract class TicketDecorator impiments Component {
    //用于装饰的私有对象
    private Component myTrailer;
    //构造方法,使用时传入装饰对象
    public TicketDecorator(Component myComponent) {
        super();
        myTrailer = myComponent;
    }
    public void callTrailer() { //与抽象接口功能一致:打印票据
        if (myTrailer != null) {
            myTrailer.printTicket();
        }
    }
}
//具体装饰:负责给票据对象贴上附加的功能
class Header extends TicketDecorator {
    public Header(Component myComponent) {
        super(myComponent);
    }
    @Override
    public void printTicket() {
        System.out.println("打印salesTicket的头信息"); //附加的功能
        super.callTrailer();
    }
}
//具体装饰:负责给票据对象贴上附加的功能
class Footer extends TicketDecorator {
    public Footer(Component myComponent) {
        super(myComponent);
    }
    @Override
    public void printTicket() {
        super.callTrailer();
        System.out.println("打印salesTicket的页脚信息"); //附加的功能
    }
}
public class TicketClient {
    public static void main(String[] args) { 
    //Header和Footer对原来的对象进行了装饰,客户并没有感觉到有什么不同
        System.out.println("====================================");
        new Header(new Footer(new SalesTicket())).printTicket();
        System.out.println("====================================");
        new Footer(new Header(new SalesTicket())).printTicket();
        System.out.println("====================================");
    }
}

6.组合模式Composite

组合模式将对象组合成树形结构以表示“部分-整体”的层次结构,解决部分整体的一致性问题。例如团队和个人,团队中涉及到遍历的方法,个人没有这样的方法,但是二者又有共同的一些接口。客户端可以一致地处理对象和对象容器,无需关心处理的是单个对象还是组合对象。
  1.Component:组合模式中的元素抽象;
  2.Leaf:叶子元素,此类元素无法容乃其他元素;
  3.Composite:组合元素,可以容纳其他元素,重写Component抽象方法中的add(),remove()等与对象容器相关的方法。
  4.Client:客户端代码。使用Component来操作所有组合部件对象Leaf和Composite;
Component是组合模式的顶级抽象,最大化接口设计,包括所有实现类的全部功能,给某些并不是所有类都用到的方法设计一个默认的实现。默认的方法可以被重写。默认方法是不支持的,组合对象需要重写这些方法。
实现

import java.util.ArrayList;

//节目列表,抽象类,Component
abstract class MovieClass {  //树角色Component:子树和树叶都从它继承

    public String name;
    public ArrayList<MovieClass> list;  //要操作的子树或树叶列表

    public abstract void add(MovieClass component); //增删操作

    public abstract void remove(MovieClass component);

    public abstract void display();
}

//单个节目,leaf
class Program extends MovieClass { //树叶Leaf:单个对象 

    public Program(String name) {
        this.name = name;
    }

    @Override
    public void add(MovieClass component) { //树叶不能再添加或删除子树
        System.out.println("you can't add component to a proagram object");
    }

    @Override
    public void display() {
        System.out.println("----------" + name);
    }

    @Override
    public void remove(MovieClass component) {
        System.out.println("you can't remove component to a proagram object");
    }

}

//复合节目列表,Composite
class ConcreteMovieClass extends MovieClass { //子树Composite:复合对象

    public ConcreteMovieClass(String name) {
        this.name = name;
        list = new ArrayList<>();
    }

    @Override
    public void add(MovieClass component) {
        list.add(component);
    }

    @Override
    public void remove(MovieClass component) {
        if (list.contains(component)) {
            list.remove(component);
        }
    }

    @Override
    public void display() { //复合对象的显示可以用Iterator模式
        System.out.println(name);
        for (MovieClass mc : list) {
            mc.display();
        }
    }
}

//客户程序
public class MovieClient {

    public static void main(String args[]) {
        Program pro = new Program("大汉天子");
        Program pro2 = new Program("贞观长歌");
        ConcreteMovieClass cmc = new ConcreteMovieClass("电视连续剧");//一级分类
        cmc.add(pro);
        cmc.add(pro2);

        Program pro3 = new Program("满城尽带黄金甲");
        Program pro4 = new Program("色戒");
        ConcreteMovieClass cmc2 = new ConcreteMovieClass("最新影视");//一级分类
        cmc2.add(pro3);
        cmc2.add(pro4);

        Program pro5 = new Program("越狱");
        Program pro6 = new Program("英雄");
        ConcreteMovieClass secondCmc = new ConcreteMovieClass("热播美剧");//二级分类
        secondCmc.add(pro5);
        secondCmc.add(pro6);

        cmc2.add(secondCmc);//在一级分类(最新影视)下添加二级分类热播美剧
        ConcreteMovieClass root = new ConcreteMovieClass("root");
        root.add(cmc);
        root.add(cmc2);
        root.display();//递归显示节目列表
    }
}

7.享元模式Flyweight

享元模式使用共享技术有效地支持大量的细粒度对象。在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象。
在Flyweight模式中,由于要产生各种各样的对象,所以在Flyweight(享元)模式中常出现Factory模式。Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个对象存储池(Flyweight Pool)来存放内部状态的对象。
  1、抽象享元(Flyweight)角色:此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口,通过这个接口Flyweight可以接受并作用于外部状态(Extrinsic State)。
  2、具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定的接口。如果有内蕴状态(Intrinsic State)的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享的。
  3、享元工厂(FlyweightFactory)角色:本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
  4、客户端(Client)角色:本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外蕴状态。
实现:

//单纯Flyweight
import java.util.HashMap;

//"Flyweight":抽象的享元
abstract class MyCharacter {
    //内蕴状态
    protected char symbol;  //同时也是获取享元的标识
    protected int width;
    protected int height;
    protected int ascent;
    protected int descent;
    //外蕴状态,通过下面方法的参数传入
    protected int pointSize;
    public abstract void Display(int pointSize);
}

//"ConcreteFlyweight":具体享元
class CharacterA extends MyCharacter {
    //  Constructor:为内蕴状态分成存储空间
    public CharacterA() {
        this.symbol = 'A';
        this.height = 100;
        this.width = 120;
        this.ascent = 70;
        this.descent = 0;
    }
    @Override
    public void Display(int pointSize) { //外蕴状态通过方法参数传入
        this.pointSize = pointSize;
        System.out.println(this.symbol + " (pointsize " + this.pointSize + ")");
    }
}

//"ConcreteFlyweight"
class CharacterB extends MyCharacter {
    //  Constructor
    public CharacterB() {
        this.symbol = 'B';
        this.height = 100;
        this.width = 140;
        this.ascent = 72;
        this.descent = 0;
    }
    @Override
    public void Display(int pointSize) {
        this.pointSize = pointSize;
        System.out.println(this.symbol + " (pointsize " + this.pointSize + ")");
    }
}
//C, D, E, etc.
//"ConcreteFlyweight"
class CharacterZ extends MyCharacter {
    //  Constructor
    public CharacterZ() {
        this.symbol = 'Z';
        this.height = 100;
        this.width = 100;
        this.ascent = 68;
        this.descent = 0;
    }
    @Override
    public void Display(int pointSize) {
        this.pointSize = pointSize;
        System.out.println(this.symbol + "(pointsize " + this.pointSize + ")");
    }
}
//"FlyweightFactory":享元工厂,负责创建和管理享元,必须保证享元对象可以被系统适当地共享
class MyCharacterFactory {

    private HashMap<Character, MyCharacter> characters = new HashMap<>(); //维护一个共享的享元池

    //Uses "lazy initialization":有则直接返回,没有则创建一个,可见池中每个具体享元
    //可保证只有一个实例
    public MyCharacter GetMyCharacter(char key) {
        MyCharacter character = characters.get(key);
        if (character == null) { //池中没有所要的享元,则用具体享元类来创建,并加入池中
            switch (key) {
                case 'A':
                    character = new CharacterA();
                    break;
                case 'B':
                    character = new CharacterB();
                    break;
                case 'Z':
                    character = new CharacterZ();
                    break;
            }
            characters.put(key, character);
        }
        return character; //返回由工厂创建的享元
    }
}
//Test application
public class MyCharacterTest {

    public static void main(String[] args) {
        //Build a document with text
        String document = "AAZZBBZB";
        char[] chars = document.toCharArray();
        MyCharacterFactory f = new MyCharacterFactory(); //创建一个享元工厂
        //Extrinsic state
        int pointSize = 10;
        //For each character use a flyweight object
        for (char c : chars) {
            pointSize++;
            MyCharacter character = f.GetMyCharacter(c); //根据传入的享元标识从工厂中获得一个享元
            character.Display(pointSize);
        }
    }
}

复合享元模式:采用组合模式的思想和享元模式结合。

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页