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

55 篇文章 0 订阅
47 篇文章 0 订阅

        设计模式(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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值