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("添加的功能:会飞"); } }
二、外观模式(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("统一上传,打印回执"); } }
三、享元模式(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; } }
四、组合模式(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(); } } }
安全方式:
将管理子构件的方法移到树枝构件中,避免上一种方式的安全性问题。由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,失去了透明性。
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(); } } }
以上是关于GOF 23设计模式之(结构型模式二)的主要内容,如果未能解决你的问题,请参考以下文章