個(gè)人博客: http://zhangsunyucong.top
前言
本篇文章主要講23種設(shè)計(jì)模式中的7種結(jié)構(gòu)型設(shè)計(jì)模式扶歪,包括適配器模式怀挠,裝飾者模式狡孔,代理模式,外觀模式蜓堕,橋接模式抛虏,組合模式,享元模式套才。
適配器模式
適配器模式是將一個(gè)類的方法接口轉(zhuǎn)換成客戶端期望的接口表示迂猴。我們可以約定,把客戶端期望的接口叫做目標(biāo)Targetable背伴,被轉(zhuǎn)換的類叫source沸毁。適配器模式可以分為:類的適配器模式,對(duì)象的適配器傻寂,接口的適配器息尺。
類的適配器模式
已有的被轉(zhuǎn)換的類:
public class SourceClass {
public void method1() {
System.out.print("Hi, I am a method in sourceClass");
}
}
期望的目標(biāo):
public interface Targetable {
void method1();
void method2();
}
實(shí)現(xiàn)目標(biāo),進(jìn)行適配
public class AdapterClass extends SourceClass implements Targetable {
@Override
public void method2() {
System.out.print("Hi All, I am a method in adapterClass");
}
}
這樣子就將SourceClass按照意愿Targetable適配轉(zhuǎn)換成了AdapterClass疾掰,AdapterClass具有了SourceClass的所有的功能搂誉,同時(shí)也達(dá)到了擴(kuò)展SourceClass。由于類的適配器模式是通過繼承實(shí)現(xiàn)的静檬,它具有了繼承的優(yōu)缺點(diǎn)炭懊。關(guān)于缺點(diǎn),比如通過AdapterClass對(duì)象可以調(diào)用屬于SourceClass而在Targetable接口中沒有的方法拂檩。
對(duì)象的適配器模式
對(duì)象的適配器模式侮腹,就是將原來類的對(duì)象轉(zhuǎn)換為目標(biāo)接口的對(duì)象。對(duì)象適配器模式?jīng)]有繼承被轉(zhuǎn)換類稻励,而是持有被轉(zhuǎn)換類的對(duì)象父阻。這可以避免繼承被帶來的副作用。
public class AdapterObjectClass implements Targetable{
private SourceClass mSourceClass;
public AdapterObjectClass(SourceClass mSourceClass) {
this.mSourceClass = mSourceClass;
}
@Override
public void method2() {
System.out.print("hi all, i am a method in AdapterObjectClass");
}
@Override
public void method1() {
mSourceClass.method1();
}
}
接口的適配器模式
當(dāng)一個(gè)接口有很多的抽象方法時(shí)钉迷,當(dāng)我們寫這個(gè)接口的實(shí)現(xiàn)類至非,必須實(shí)現(xiàn)該接口的全部方法。而有時(shí)候接口中并不是所有的抽象方法都是我們必須的糠聪,而我們只需要實(shí)現(xiàn)其中的某一些方法。為了解決這個(gè)問題谐鼎,我們可以使用接口的適配器模式舰蟆,引入一個(gè)抽象類趣惠,這個(gè)抽象類提供了接口所有抽象方法的空實(shí)現(xiàn)。我們可以繼承這個(gè)抽象類身害,并只重寫我們需要的方法即可味悄。
比如,在上面我們只要Targetable的method2方法塌鸯。
public abstract class AdapterInterfaceClass implements Targetable{
@Override
public void method1() {
}
@Override
public void method2() {
}
}
public class AdapterWraper extends AdapterInterfaceClass {
@Override
public void method1() {
System.out.print("hi all, I am a method in AdapterWraper class");
}
}
裝飾者模式
裝飾者模式的核心思想是侍瑟,裝飾者和被裝飾者實(shí)現(xiàn)同一個(gè)接口,將被裝飾者注入裝飾者中丙猬,可以在裝飾者中擴(kuò)展被裝飾者涨颜。
public interface Person {
void eat();
}
被裝飾者:
public class Man implements Person {
@Override
public void eat() {
System.out.print("There is a man who is eating");
}
}
裝飾者:
public class ManDecorator implements Person {
private Person mPerson;
public ManDecorator(Person person) {
mPerson = person;
}
@Override
public void eat() {
mPerson.eat();
drinkWater();
System.out.print("I finish my lunch");
}
private void drinkWater() {
System.out.print("Man is drinking water");
}
}
使用:
Man man = new Man();
ManDecorator manDecorator = new ManDecorator(man);
manDecorator.eat();
輸出的結(jié)果:
There is a man who is eating
Man is drinking water
I finish my lunch
代理模式
注意區(qū)別代理模式和動(dòng)態(tài)代理。
生活中代理的例子茧球。比如如果你要租房子庭瑰,你可能不知道該地區(qū)的房子信息,這時(shí)你可以找一個(gè)熟悉的人來幫忙抢埋,這個(gè)幫你的人就是代理弹灭;又比如,打官司時(shí)揪垄,我們可能并不精通法律知識(shí)穷吮,這時(shí)我們可以找一個(gè)代理律師來幫我們。等等饥努。酒来。對(duì)于,代理的工作可以抽象為一個(gè)接口肪凛。
public interface WorkInterface {
void rentHouse();
}
一個(gè)房東:
public class LandLady implements WorkInterface {
@Override
public void rentHouse() {
System.out.print("您好堰汉!我是房東。我這里有房子出租伟墙!");
}
}
代理房東的代理類:
public class Proxy implements WorkInterface {
private LandLady mLandLady;
public Proxy() {
mLandLady = new LandLady();
}
@Override
public void rentHouse() {
mLandLady.rentHouse();
}
}
租客去找代理租房子:
WorkInterface proxy = new Proxy();
proxy.rentHouse();
外觀模式
在醫(yī)院里的前臺(tái)接待員就是一個(gè)外觀模式的體現(xiàn)翘鸭。由于病人來到醫(yī)院可能對(duì)醫(yī)院內(nèi)部和流程并不熟悉,那么可以由熟悉這些的接待員來幫病人來完成這些事情戳葵。
部門1
public class ModuleA {
//提供給外部調(diào)用的方法
public void a1() {}
//內(nèi)部完成工作的實(shí)現(xiàn)
private void a2() {}
private void a3() {}
}
部門2
public class ModuleB {
//提供給外部調(diào)用的方法
public void b1() {}
//內(nèi)部完成工作的實(shí)現(xiàn)
private void b2() {}
private void b3() {}
}
部門3
public class ModuleC {
//提供給外部調(diào)用的方法
public void c1() {}
//內(nèi)部完成工作的實(shí)現(xiàn)
private void c2() {}
private void c3() {}
}
外觀類:
public class ModuleFacade {
private ModuleA mModuleA = new ModuleA();
private ModuleB mMBModuleB = new ModuleB();
private ModuleC mMCModuleC = new ModuleC();
public void a1() {
mModuleA.a1();
}
public void b1() {
mMBModuleB.b1();
}
public void c1() {
mMCModuleC.c1();
}
}
當(dāng)我們需要ModuleA就乓,ModuleB, ModuleC的功能時(shí)拱烁,我們并不直接和他們打交道生蚁,也不需要了解部門的功能是如何實(shí)現(xiàn)的,而我們只需要去找外觀類溝通即可戏自。
外觀模式的關(guān)鍵點(diǎn)是整合邦投。
橋接模式
橋接模式,提供一個(gè)解耦或者連接抽象化和實(shí)現(xiàn)化的一個(gè)橋梁擅笔,使得二者可以獨(dú)立變化志衣。
一個(gè)接口作為橋屯援,一個(gè)抽象類持有橋。橋和抽象類兩者可以獨(dú)立變化念脯。
橋:
public interface Qiao {
void toArea();
}
抽象類:
public abstract class FromArea {
public Qiao qiao;
abstract public void fromArea();
}
QiaoC.java
public class QiaoC implements Qiao {
@Override
public void toArea() {
System.out.print("I want to go Area C");
}
}
QiaoD.java
public class QiaoD implements Qiao {
@Override
public void toArea() {
System.out.print("I want to go Area D");
}
}
FromAreaA.java
public class FromAreaA extends FromArea {
@Override
public void fromArea() {
System.out.print("I come from area A");
}
}
FromAreaB.java
public class FromAreaB extends FromArea {
@Override
public void fromArea() {
System.out.print("I come from area B");
}
}
使用:
FromAreaA fromAreaA = new FromAreaA();
QiaoC qiaoC = new QiaoC();
fromAreaA.qiao = qiaoC;
fromAreaA.fromArea();
fromAreaA.qiao.toArea();
QiaoD qiaoD = new QiaoD();
fromAreaA.qiao = qiaoD;
fromAreaA.fromArea();
fromAreaA.qiao.toArea();
從上面可以看出狞洋,Qiao和FromArea兩者是獨(dú)立變化的,它們的抽象和實(shí)現(xiàn)是分離的绿店。
如果有更多的Qiao和FromArea的實(shí)現(xiàn)吉懊,只要擴(kuò)展它們即可。
組合模式
組合模式假勿,又叫“整體-部分設(shè)計(jì)模式”借嗽。它一般用于實(shí)現(xiàn)樹形結(jié)構(gòu)。
節(jié)點(diǎn)
public class TreeNode {
private String name;
private TreeNode parent;
private Vector<TreeNode> children = new Vector<>();
public TreeNode(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setParent(TreeNode parent) {
this.parent = parent;
}
public TreeNode getParent() {
return parent;
}
public void addChild(TreeNode child) {
children.add(child);
}
public boolean removeChild(TreeNode child) {
return children.remove(child);
}
public Enumeration<TreeNode> getChildren() {
return children.elements();
}
}
整體废登,建立一棵樹:
public class Tree {
TreeNode root = null;
public Tree(String name) {
root = new TreeNode(name);
}
public static void main(String[] args) {
Tree tree = new Tree("A");
TreeNode nodeB = new TreeNode("B");
TreeNode nodeC = new TreeNode("C");
nodeB.addChild(nodeC);
tree.root.addChild(nodeB);
System.out.println("build the tree finished!");
}
}
享元模式
享元模式主要是實(shí)現(xiàn)對(duì)象的共享淹魄。聯(lián)想數(shù)據(jù)庫的連接池。
public class ConnectionPool {
private Vector<Connection> pool;
/*公有屬性*/
private String url = "jdbc:mysql://localhost:3306/test";
private String username = "root";
private String password = "root";
private String driverClassName = "com.mysql.jdbc.Driver";
private int poolSize = 100;
private static ConnectionPool instance = null;
Connection conn = null;
/*構(gòu)造方法堡距,做一些初始化工作*/
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);
}
/* 返回連接池中的一個(gè)數(shù)據(jù)庫連接 */
public synchronized Connection getConnection() {
if (pool.size() > 0) {
Connection conn = pool.get(0);
pool.remove(conn);
return conn;
} else {
return null;
}
}
}