JAVA之设计模式(结构型模式)

来源:互联网 发布:中国高铁无砟 知乎 编辑:程序博客网 时间:2024/06/03 10:52
        设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编写真正工程化,设计模式是软件工程的基石,如同大厦的设计图一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。

一、设计模式的六大原则

        1、开闭原则(Open Close Principle)

        开闭原则就是说:对扩展开放,对修改关闭。在程序需要进行扩展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

        2、依赖倒转原则(Dependence Inversion Principle)

        依赖倒转原则就是说:针对接口编程,依赖于抽象而不依赖于具体。它是开闭原则的基础。

        3、里氏代换原则(Liskov Substitution Principle)

        里氏代换原则就是说:任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。       

        4、接口隔离原则(Interface Segregation Principle)

        接口隔离原则就是说:使用多个隔离的接口,比使用单个接口要好。其实也就是降低类之间的耦合度的意思。

        5、合成复用原则(Composite Reuse Principle)

        合成复用原则就是说:尽量使用合成/聚合的方式,而不是使用继承。

        6、迪米特原则(最少知道原则)(Demeter Principle)

        迪米特原则就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

二、设计模式的分类与应用

        总体来说设计模式分为三大类(23种):

结构型模式(7种):适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

        1、适配器模式:将原有类或接口转换成客户端期望的类或接口,目的是消除由于接口不匹配所造成的类兼容性问题。分3种:

        1>类适配器模式:适配器类实现了目标接口,并且继承了被适配的类。适配器类与被适配的类是一种继承关系。此模式由3部分组成:

        ①目标接口:即客户期望成的接口。

public interface Animal{public void say();}

        目标接口的实现:

public class OrdinaryAnimal implements Animal{public void say() {System.out.println("普通动物的叫声");}}

        ②被适配的类:即通过目标接口也能访问的类

public class People {public void speak(){System.out.println("人类的语言");}}

        ③适配器类:

public class PeopleAdapter extends People implements Animal {public void say(){super.speak();}}

        主入口:

public class Test {public static void main(String[] args) {Animal animal1 = new OrdinaryAnimal();animal1.say();Animal animal2 = new PeopleAdapter();animal2.say();}}

        2>对象适配器模式:适配器类实现了目标接口,并且将被适配的类的作为适配器类的成员变量。适配器类与被适配的类是一种包含关系。此模式由3部分组成:

        ①目标接口:即客户期望成的接口。

public interface Animal{public void say();}

        目标接口的实现:

public class OrdinaryAnimal implements Animal{public void say() {System.out.println("普通动物的叫声");}}

        ②被适配的类:即通过目标接口也能访问的类

public class People {public void speak(){System.out.println("人类的语言");}}

        ③适配器类:

public class PeopleAdapter implements Animal {private People people;public PeopleAdapter(People people){this.people=people;}public void say() {people.speak();}}

        主入口:

public class Test {public static void main(String[] args) {Animal animal1 = new OrdinaryAnimal();animal1.say();People people = new People();Animal animal2 = new PeopleAdapter(people);animal2.say();}}

        双向适配器:如果目标接口需要被适配的类适配,而被适配的类也需要目标接口适配,那么就需要将目标接口和被适配的类都作为适配器类的成员变量。

        3>缺省适配器模式(单接口适配器模式):当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用接口中的所有方法的情况。

        ①原接口:

public interface Animal{public void say();public void run();public void fly();}

        ②抽象类:

public abstract class AnimalClass implements Animal {public void say(){}public void run(){}public void fly(){}}

        ③继承类1:

public class People extends AnimalClass{public void say(){System.out.println("人类的语言");}public void run(){System.out.println("使用双腿奔跑");}}

        继承类2:

public class Bird extends AnimalClass {public void say(){System.out.println("鸟的语言");}public void fly(){System.out.println("使用翅膀飞翔");}}

        主入口:

public class Test {public static void main(String[] args) {Animal people = new People();people.say();people.run();Animal bird = new Bird();bird.say();bird.fly();}}

        2、装饰模式:动态地给一个对象增加一些额外的功能,就增加对象功能来说,装饰模式比添加继承子类实现更为灵活。此模式由4部分组成:

        ①抽象构件接口:被装饰类和装饰类都会实现此接口,实现统一管理。

public interface Animal {public void act();}

        ②被装饰类:原有的功能,需要在此基础上新增功能。

public class People implements Animal{public void act(){System.out.println("我可以用双脚走路");}}

        ③抽象装饰类:将构件接口作为本类的成员变量,通过此变量可以调用装饰之前的功能,而实际新增功能是在其子类中实现的。

public class SuperMan implements Animal{private Animal animal;public SuperMan(Animal animal){this.animal=animal;}public void act() {animal.act();}}

        ④具体装饰类:

public class IronMan extends SuperMan {public IronMan(Animal animal){super(animal);}public void act() {super.act();this.addAct();}public void addAct(){System.out.println("我还可以在天空飞");}}

        主入口:

public class Test {public static void main(String[] args) {Animal animal1 = new People();Animal animal2 = new IronMan(animal1);animal2.act();}}

        透明装饰模式:要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型。透明装饰模式可以对一个已装饰过的对象进行多次装饰,得到更为复杂、功能更为强大的对象。

        半透明装饰模式:要求客户端程序必须使用具体的装饰类型(具体装饰类)定义被装饰后的对象,所以不能对一个已装饰过的对象进行多次装饰。

        3、代理模式:使用代理对象来替代实际对象,代理对象和实际对象要实现同一个接口。此模式由3部分组成:

        ①接口:声明了代理对象和实际对象的共同接口。

public interface Human{public void act();}

        ②实际对象:包含实际的业务。

public class RealPeople implements Human{public void act(){System.out.println("我是真正的幕后老大");}}

        ③代理对象:包含对实际对象的引用,从而在任何时候都可以操作实际对象。

public class proxyPeople implements Human {private Human human;public proxyPeople(){this.human=new RealPeople();}public void act() {human.act();}}

        主入口:

public class Test {public static void main(String[] args) {Human people = new ProxyPeople();people.act();}}

        4、外观模式:对多个对象的访问都是通过同一个对象统一管理统一访问。此模式由2部分组成:

        ①子系统角色1:

public class CPU {public void startup(){System.out.println("cpu startup!");}public void shutdown(){System.out.println("cpu shutdown!");}}

        子系统角色2:

public class Memory {public void startup(){System.out.println("memory startup!");}public void shutdown(){System.out.println("memory shutdown!");}}

        子系统角色3:

public class Disk {public void startup(){System.out.println("disk startup!");}public void shutdown(){System.out.println("disk shutdown!");}}

        ②外观角色:

public class Computer {private CPU cpu;private Memory memory;private Disk disk;public Computer(){cpu = new CPU();memory = new Memory();disk = new Disk();}public void startup(){System.out.println("start the computer!");cpu.startup();memory.startup();disk.startup();System.out.println("start computer finished!");}public void shutdown(){System.out.println("begin to close the computer!");cpu.shutdown();memory.shutdown();disk.shutdown();System.out.println("computer closed!");}}

        主入口:

public class Test {public static void main(String[] args) {  Computer computer = new Computer();  computer.startup();  computer.shutdown();  }  }

            5、桥接模式:当某个类同时存在两个独立变化的维度时,需要将这两个维度分离开,使两者可以独立扩展。此模式由4部分组成:

        ①维度1的抽象类:将维度2作为一个成员变量。

public abstract class Pen {protected Draw draw;Pen(Draw draw){this.draw=draw;}public abstract void draw();}

        ②维度1的子类1:

public class Pen1 extends Pen {Pen1(Draw draw){super(draw);}public void draw() {System.out.println("第1种笔正在画");this.draw.drawCircle();}}

        维度1的子类2:

public class Pen2 extends Pen {Pen2(Draw draw){super(draw);}public void draw() {System.out.println("第2种笔正在画");this.draw.drawSquare();}}

        维度1的子类3:

public class Pen3 extends Pen {Pen3(Draw draw){super(draw);}public void draw() {System.out.println("第3种笔正在画");this.draw.drawTriangle();}}

        ③维度2的接口:

public interface Draw {public void drawCircle();public void drawSquare();public void drawTriangle();}

        ④维度2的实现1:

public class Draw1 implements Draw {public void drawCircle() {System.out.println("画圆的第1种画法");}public void drawSquare() {System.out.println("画矩形的第1种画法");}public void drawTriangle() {System.out.println("画三角形的第1种画法");}}

        维度2的实现2:

public class Draw2 implements Draw {public void drawCircle() {System.out.println("画圆的第2种画法");}public void drawSquare() {System.out.println("画矩形的第2种画法");}public void drawTriangle() {System.out.println("画三角形的第2种画法");}}

        维度2的实现3:

public class Draw3 implements Draw {public void drawCircle() {System.out.println("画圆的第3种画法");}public void drawSquare() {System.out.println("画矩形的第3种画法");}public void drawTriangle() {System.out.println("画三角形的第3种画法");}}

        主入口:

public class Test {public static void main(String[] args) {Draw draw1 = new Draw1();Draw draw2 = new Draw2();Draw draw3 = new Draw3();Pen pen1 = new Pen1(draw1);Pen pen2 = new Pen2(draw2);Pen pen3 = new Pen3(draw3);pen1.draw();pen2.draw();pen3.draw();}}

            6、组合模式:也叫部分-整体模式,即组合对象的结构和单个对象的结构是相同的。此时本类的对象作为本类中的一个成员变量,常用于树结构或文件目录中的节点。

TreeNode:

import java.util.Vector;public class TreeNode {private TreeNode parentNode;private String nodeName;private Vector<TreeNode> childNodes=new Vector<TreeNode>();TreeNode(String name){this.nodeName = name;}public TreeNode getParentNode() {return parentNode;}public void setParentNode(TreeNode parentNode) {this.parentNode = parentNode;}public String getNodeName() {return nodeName;}public void setNodeName(String nodeName) {this.nodeName = nodeName;}public Vector<TreeNode> getChildNodes() {return childNodes;}public void setChildNodes(Vector<TreeNode> childNodes) {this.childNodes = childNodes;}public void addNode(TreeNode node){this.childNodes.add(node);}public void delNode(int num){this.childNodes.remove(num);}public String getChildNodeNames(TreeNode node){ String nodes = "";for(TreeNode tmp:node.childNodes){nodes+=tmp.getNodeName()+","+tmp.getChildNodeNames(tmp);}return nodes;}  }

Tree:

public class Tree {static TreeNode root = new TreeNode("root");public static void main(String[] args) {TreeNode node1 = new TreeNode("node1");TreeNode node11 = new TreeNode("node11");TreeNode node12 = new TreeNode("node12");TreeNode node2 = new TreeNode("node2");TreeNode node21 = new TreeNode("node21");TreeNode node22 = new TreeNode("node22");TreeNode node221 = new TreeNode("node221");root.addNode(node1);root.addNode(node2);node1.addNode(node11);node1.addNode(node12);node2.addNode(node21);node2.addNode(node22);node22.addNode(node221);System.out.println(root.getChildNodeNames(root));}}

            7、享元模式:主要目的是实现对象的共享,即共享池,当系统中有相应的对象时就不再创建该对象,因此可以减少内存的开销,通常与工厂模式一起使用。

import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.util.Vector;public class ConnectionPool{private Vector<Connection> pool;private int poolSize = 10;Connection conn = null;private String url = "jdbc:mysql://localhost:3306/test";private String username = "root";private String password = "root";private String driverClassName = "com.mysql.jdbc.Driver";private ConnectionPool() {pool = new Vector<Connection>(poolSize);for (int i = 0; i < poolSize; i++) {try {Class.forName(driverClassName);conn = DriverManager.getConnection(url, username, password);pool.add(conn);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();}}}//释放回到连接池 public synchronized void release() {pool.add(conn);}//得到连接池中的一个数据库连接 public synchronized Connection getConnection() {if (pool.size() > 0) {Connection conn = pool.get(0);pool.remove(conn);return conn;} else {return null;}}}

0 0