GOF 23设计模式之(结构型模式二)

Posted huangcan1688

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GOF 23设计模式之(结构型模式二)相关的知识,希望对你有一定的参考价值。

目录

1.装饰模式

2.外观模式

3.享元模式

4.组合模式

4.1透明方式

4.2安全方式

 

 

一、装饰模式(Decorator)

  可以动态的为对象添加新的功能,是一种用于代替继承的技术,无须通过继承添加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系。同时避免类型体系的快速膨胀。

 

  核心角色:

  (1)抽象构件角色(Component):定义一个抽象的接口以规范准备接收附加责任的对象。

  (2)具体构件角色(Concrete Component):实现抽象化构件,通过装饰角色为其添加一些职责。

  (3)抽象装饰角色(Decorator):实现抽象构件,并包含具体构件的实例。可以通过其子类扩展具体构件的功能。

  (4)具体装饰角色(Concrete Decorator):继承抽象装饰的相关方法,并给具体构件对象添加附加的责任。

 

  优点:

  (1)装饰模式扩展的功能比继承方式要灵活。

  (2)可以设计出多个不同的具体装饰类,创建出不同行为的组合。

 

  缺点:

  (1)装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。

 

  技术图片

技术图片
public class textDecorator {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

    
        //原来的功能
        Component car = new ConcreteComponent();
        car.operation();
        
        //进过装饰
        Component carbefore = new ConcreteDecorator(car);
        carbefore.operation(); //装饰了新的功能
    }
}

//模拟一个车的改装

//抽象构件角色
interface Component{//车,能开
    
    public void operation();
}

//具体构件角色
class ConcreteComponent implements Component{

    @Override
    public void operation() {
        System.out.println("奥迪可以在陆地上飞快的行驶。");
    }
}

//抽象装饰角色
class Decorator implements Component{
    
    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {//获取到原来的功能
        component.operation();
    }
}

//具体装饰角色
class ConcreteDecorator extends Decorator{

    public ConcreteDecorator(Component component) {
        super(component);
    }
    
    public void operation() {
        super.operation();//继承拿到原来的功能
        addedFunction();//装饰新的功能
    }
    
    //新的功能
    public void addedFunction() {
        System.out.println("添加的功能:会飞");
    }
    
}
View Code

返回顶部

 

二、外观模式(Facade)

   为系统提供统一的入口,封装系统的复杂性,便于客户端的使用。

 

  核心角色:

  (1)外观角色(Facade):为多个子系统对外提供一个共同的接口。

  (2)子系统角色(Sub System):实现系统的部分功能,客户可以通过外观角色访问它。

  (3)客户角色(Client):通过外观访问角色访问各个子系统的功能。

 

  优点:(迪米特原则的典型应用)

  (1)降低子系统与客户端的耦合度,使得子系统的变化不会影响调用它的客户类。

  (2)可客户屏蔽了子系统组件,减少了客户处理的对象数目,使用更容易。

  (3)降低了大型软件系统的编译依赖性,简化了系统在不同平台的移植过程。

 

  缺点:

  (1)不能很好地限制客户使用子系统。

  (2)增加新的子系统时,可能需要改变外观类或客户端源代码,违背了开闭原则。

 

   技术图片

技术图片
public class textFacade {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        //现在所有的流程都需要在一个门面里面就可以操作了
        Facade f = new Facade();
        f.method();
    }
}

//模拟:身份证的办理

class Facade{
    
    private SubSystem01 obj1 = new SubSystem01();//拍照
    private SubSystem02 obj2 = new SubSystem02();//复印件
    private SubSystem03 obj3 = new SubSystem03();//上传拿回执
    
    public void method() {//门面统一操作
        
        obj1.method1();
        obj2.method2();
        obj3.method3();
    }
}

//子系统
class SubSystem01{
    
    public void method1() {
        System.out.println("统一拍照");
    }
}

class SubSystem02{
    
    public void method2() {
        System.out.println("统一打印复印件");
    }
}

class SubSystem03{
    
    public void method3() {
        System.out.println("统一上传,打印回执");
    }
}
View Code

返回顶部

 

三、享元模式(Flyweight)

    运用共享的技术高效的支持大量细粒度对象的重用。通过共享已经存在的对象来减少大量需要创建的对象数量。从而提高系统资源的利用率。

  享元模式能做到共享的关键:区分内部和外部的状态。

  内部状态可以共享,不会随着环境的变化而变化。外部状态则反之。

 

  核心角色:

  (1)抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。

  (2)具体享元角色(Concrete Flyweight):实现抽象享元角色中规定的接口

  (3)非享元角色(Unsharable Flyweight):是不可以共享的外部状态,以参数的形式注入具体享元的相关方法中

  (4)享元工厂角色(Flyweight Factory):负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检查系统中是否有符合要求的享元对象,如果存在则提供给客户,反之,创建一个新的享元对象。

 

  优点:

  (1)相同的对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存的压力。

 

  缺点:

  (1)为了使用对象可以共享,需要将一些不共享的状态外部化,增加了程序的复杂性。

  (2)读取享元模式的外部状态会使得运行时间稍微变长。

 

  技术图片

技术图片
public class textFlyweight {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        //像一幅棋子中,棋子的颜色、大小等都是可以共享的。

        FlyweightFactory factory = new FlyweightFactory();
        Flyweight f01 = factory.getFlyweight("白色棋子");//创建享元对象
        Flyweight f02 = factory.getFlyweight("白色棋子");//创建享元对象
        Flyweight f03 = factory.getFlyweight("黑色棋子");//创建享元对象
        
        f01.operation(new UnsharedConcreteFlyweight("棋子《车》"));
        f03.operation(new UnsharedConcreteFlyweight("棋子《车》"));
        
    }
}

//模拟:一个棋盘上的棋子的大小和颜色是可以共享的。位置是不可以共享的。

//抽象享元角色
interface Flyweight{
    
    public void operation(UnsharedConcreteFlyweight state);
}

//非享元角色
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;
    }
    
}

//具体享元角色
class ConcreteFlyweight implements Flyweight{

    private String key;
    
    public ConcreteFlyweight(String key) {
        this.key = key;
        System.out.println("具体享元<"+key+">被创建");
    }

    @Override
    public void operation(UnsharedConcreteFlyweight outState) {
        System.out.print("具体享元<"+key+">被调用,");
        System.out.println("非享元信息<"+outState.getInfo()+">");
    }

    
}

//享元工厂角色
class FlyweightFactory{
    
    private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
    
    public Flyweight getFlyweight(String key) {
        
        Flyweight flyweight = flyweights.get(key);
        
        if(flyweight != null) {
            
            System.out.println("具体享元<"+key+">已经存在,被成功获取");
        }else {
            flyweight = new ConcreteFlyweight(key);
            flyweights.put(key, flyweight);
        }
        
        return flyweight;
    }
}
View Code

返回顶部

 

四、组合模式(Composite)

   把部分和整体的关系用树形结构来表示,从而使客户端可以使用统一的方式去处理部分对象和整体对象。

  可以分为:透明方式、安全方式。

 

  核心角色:

  (1)抽象构件角色(Component):为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式中,抽象构件还声明访问和管理子类的接口。在安全式中,不声明访问和管理子类的接口,管理工作由树枝完成。

  (2)树叶构件角色(Leaf):是组合中的叶节点对象,它没有子节点,用于实现抽象构件角色中声明的公共接口。

  (3)树枝构件角色(Composite):是组合中的分支节点对象,有子节点。实现了抽象构件角色中声明的公共接口,主要作用是存储和管理子部件,通常包含Add()、Remove()、GeChild()等方法。

 

  优点:

  (1)使得客户端可以一致的处理单个对象和组合对象,无需关心自己处理的是单个对象还是组合对象,简化了客户端代码。

  (2)更容易在组合体内加入新对象,客户端不会因为加入了新的对象而更改源代码,满足开闭原则。

    

  缺点:

  (1)设计复杂,客户端需要花更多的时间理清类之间的层次关系。

  (2)不容易限制容器中的构件。

  (3)不容易用继承的方法来增加构件的新工能。

 

  透明方式:

    由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但是缺点是:树叶构件本来没有Add()、Remove()、GetChild()方法,却要实现它们(空实现或抛异常),这样会带来一下安全性问题。

  技术图片

技术图片
public class textComposite {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Component cp1 = new Composite();//树枝构件
        Component cp2 = new Composite();
        
        Component lef1 = new Leaf("树叶1");//树叶
        Component lef2 = new Leaf("树叶2");
        Component lef3 = new Leaf("树叶3");
        
        cp1.add(lef1); //树枝上添加树叶
        cp1.add(lef2);
        cp1.add(cp2); //树枝上添加树枝
        cp2.add(lef3);
        cp1.operation();//访问
        
    }
}

//抽象构件
interface Component{
    
    public void add(Component c); //添加构件
    public void remove(Component c);//删除构件
    public Component getChild(int i);//获取构件
    public void operation();//访问
    
}

//树叶构件
class Leaf implements Component{
    
    private String name;
    
    public Leaf(String name) {
        this.name = name;
    }

    @Override
    public void add(Component c) {}

    @Override
    public void remove(Component c) {}

    @Override
    public Component getChild(int i) {
        
        return null;
    }

    @Override
    public void operation() {
        System.out.println("树叶<"+name+">被访问");
    }
}

//树枝构件
class Composite implements Component{
    
    private ArrayList<Component> children = new ArrayList<Component>();

    @Override
    public void add(Component c) {
        children.add(c);
    }

    @Override
    public void remove(Component c) {
        children.remove(c);
    }

    @Override
    public Component getChild(int i) {
        
        return children.get(i);
    }

    @Override
    public void operation() {
        
        for (Object obj : children) {
            ((Component) obj).operation();
        }
    }
}
View Code

返回顶部

 

  安全方式:

   将管理子构件的方法移到树枝构件中,避免上一种方式的安全性问题。由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,失去了透明性。

  技术图片

 

技术图片
public class textComposite {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Composite cp1 = new Composite();//树枝构件
        Composite cp2 = new Composite();
        
        Component lef1 = new Leaf("树叶1");//树叶
        Component lef2 = new Leaf("树叶2");
        Component lef3 = new Leaf("树叶3");
        
        cp1.add(lef1); //树枝上添加树叶
        cp1.add(lef2);
        cp1.add(cp2); //树枝上添加树枝
        cp2.add(lef3);
        cp1.operation();//访问
        
    }
}

//抽象构件
interface Component{
    
    public void operation();//访问
    
}

//树叶构件
class Leaf implements Component{
    
    private String name;
    
    public Leaf(String name) {
        this.name = name;
    }

    @Override
    public void operation() {
        System.out.println("树叶<"+name+">被访问");
    }
}

//树枝构件
class Composite implements Component{
    
    private ArrayList<Component> children = new ArrayList<Component>();

    public void add(Component c) {
        children.add(c);
    }

    public void remove(Component c) {
        children.remove(c);
    }

    public Component getChild(int i) {
        
        return children.get(i);
    }

    @Override
    public void operation() {
        
        for (Object obj : children) {
            ((Component) obj).operation();
        }
    }
}
View Code

返回顶部

 

    

以上是关于GOF 23设计模式之(结构型模式二)的主要内容,如果未能解决你的问题,请参考以下文章

GOF23设计模式之适配器模式

GOF 23设计模式之(结构型模式一)

GOF23设计模式之单例模式

GOF23设计模式之访问者模式(visitor)

GOF 23设计模式之(行为型模式二)

GOF23设计模式之模板方法模式(template method)