設(shè)計(jì)模式(視頻總結(jié))
[TOC]
一抽高、簡(jiǎn)單工廠模式(Simple Factory)
簡(jiǎn)單工廠模式:
簡(jiǎn)單工廠模式屬于類的創(chuàng)建型模式潦蝇,又叫靜態(tài)工廠方法模式涉枫,通過專門定義一個(gè)類來負(fù)責(zé)創(chuàng)建其他類的實(shí)例梧田,被創(chuàng)建的實(shí)例通常都具有共同的父類萌业。
角色:
1.工廠角色
簡(jiǎn)單工廠的核心 蔚袍,它負(fù)責(zé)實(shí)現(xiàn)創(chuàng)建所有實(shí)例的內(nèi)部邏輯乡范,工廠類可以被外界直接調(diào)用創(chuàng)建所需產(chǎn)品對(duì)象。
2.抽象角色
簡(jiǎn)單工廠模式所創(chuàng)建的所有對(duì)象的父類啤咽,它負(fù)責(zé)描述所有實(shí)例的公共接口
3.具體產(chǎn)品角色
簡(jiǎn)單工廠所創(chuàng)建的具體實(shí)例對(duì)象晋辆。
//工廠角色(版本一)
public class FruitFactory {
public static Fruit getApple(){
return new Apple();
}
public static Fruit getBanana(){
return new Banana();
}
}
//抽象角色
public interface Fruit {
public void get();
}
//產(chǎn)品
public class Apple implements Fruit{
@Override
public void get() {
System.out.println("采集蘋果");
}
}
//產(chǎn)品
public class Banana implements Fruit{
@Override
public void get() {
System.out.println("采集香蕉");
}
}
//測(cè)試函數(shù)
public class Main {
public static void main(String[] args) {
Fruit apple = FruitFactory.getApple();
Fruit banana = FruitFactory.getBanana();
apple.get();
banana.get();
}
}
以上就是一個(gè)簡(jiǎn)單工廠模式
現(xiàn)對(duì)工廠角色進(jìn)行改進(jìn):
//版本二(常用)
public static Fruit getFruti(String type) throws InstantiationException, IllegalAccessException{
if(type.equalsIgnoreCase("apple")){
return Apple.class.newInstance();
}else if(type.equalsIgnoreCase("banana")){
return Banana.class.newInstance();
}else{
System.out.println("找不到響應(yīng)的類");
return null;
}
}
再改進(jìn)
//版本三
public static Fruit getFruit(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class<?> fruit = Class.forName(type);//type必須是類的完全限定名
return (Fruit) fruit.newInstance();
}
//版本三的測(cè)試程序
Fruit apple = FruitFactory.getFruit("simpleFactory_4.Apple");
Fruit banana = FruitFactory.getFruit("simpleFactory_4.Banana");
apple.get();
banana.get();
二、工廠方法模式(Factory Method)
意圖:
定義一個(gè)用于創(chuàng)建對(duì)象的接口宇整,讓子類決定實(shí)例化哪一個(gè)類瓶佳,工廠方法是一個(gè)類的實(shí)例化延遲到其子類。
適用性:
- 當(dāng)一個(gè)類不知道它所必須創(chuàng)建的對(duì)象的類的時(shí)候鳞青。
- 當(dāng)一個(gè)類希望由它的子類來制定它所創(chuàng)建的對(duì)象的時(shí)候霸饲。
- 當(dāng)類將創(chuàng)建對(duì)象的職責(zé)委托給多個(gè)幫助子類中的某一個(gè),并且你希望哪一個(gè)幫助子類是代理這一信息局部化的時(shí)候臂拓。
角色:
- 抽象工廠角色
工廠方法模式的核心厚脉,任何工廠類都必須實(shí)現(xiàn)這個(gè)借口。
- 具體工廠角色
具體工廠類是抽象工廠的一個(gè)實(shí)現(xiàn)胶惰,負(fù)責(zé)實(shí)例化產(chǎn)品對(duì)象傻工。 - 抽象角色
工廠方法模式所創(chuàng)建的所有對(duì)象的父類,它負(fù)責(zé)描述所有實(shí)例所共有的公共接口 - 具體產(chǎn)品角色
工廠方法模式所創(chuàng)建的具體的實(shí)例對(duì)象
代碼:
//抽象工廠角色
public interface FruitFactory {
public Fruit getFruit();
}
//具體工廠角色
public class AppleFactory implements FruitFactory {
@Override
public Fruit getFruit() {
return new Apple();
}
}
//具體工廠角色
public class BananaFactory implements FruitFactory {
@Override
public Fruit getFruit() {
return new Banana();
}
}
//抽象角色
public interface Fruit {
public void get();
}
//具體產(chǎn)品角色
public class Apple implements Fruit{
@Override
public void get() {
System.out.println("采集蘋果");
}
}
//具體產(chǎn)品角色
public class Banana implements Fruit{
@Override
public void get() {
System.out.println("采集香蕉");
}
}
//測(cè)試方法
public class Main {
public static void main(String[] args) {
Fruit apple = new AppleFactory().getFruit();
apple.get();
Fruit banana = new BananaFactory().getFruit();
banana.get();
}
}
工廠方法模式和簡(jiǎn)單工廠模式的比較
- 工廠方法模式與簡(jiǎn)單工廠模式在結(jié)構(gòu)上的不同不是很明顯。工廠方法類的核心是一個(gè)抽象的工廠類中捆,而簡(jiǎn)單工廠模式把核心放在一個(gè)具體的類上威鹿。
- 工廠方法模式之所以有一個(gè)別名叫多態(tài)工廠模式是因?yàn)榫唧w工廠類都有共同的接口,或者有共同的抽象父類轨香。
- 當(dāng)系統(tǒng)擴(kuò)展需要添加新的產(chǎn)品對(duì)象時(shí),僅僅需要添加一個(gè)具體對(duì)象以及一個(gè)具體工廠對(duì)象幼东,原有工廠對(duì)象不需要進(jìn)行任何修改臂容,也不需要修改客戶端,很好的復(fù)合“開放-封閉”原則根蟹,而簡(jiǎn)單工廠模式再添加新產(chǎn)品對(duì)象后不得不修改工廠方法脓杉,擴(kuò)展性不是很好。
- 工廠方法模式退化后可以演變成簡(jiǎn)單工廠模式简逮。
三球散、 抽象工廠模式(Abstract Factory)
抽象工廠模式是所有形態(tài)的工廠模式中最為抽象和最具有一般性的,抽象工廠模式可以指定向客戶端提供一個(gè)接口散庶,使得客戶端不必指定產(chǎn)品具體類型的情況下蕉堰,能夠創(chuàng)建產(chǎn)品族的產(chǎn)品對(duì)象。
意圖:
提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口悲龟,而無(wú)需指定它們具體的類屋讶。
適用性:
- 一個(gè)系統(tǒng)要獨(dú)立于它的產(chǎn)品的創(chuàng)建、組合和表示時(shí)须教。
- 一個(gè)系統(tǒng)要有多個(gè)產(chǎn)品系列中的一個(gè)來配置時(shí)皿渗。
- 當(dāng)你要強(qiáng)調(diào)一系列相關(guān)的產(chǎn)品對(duì)象的設(shè)計(jì)以便進(jìn)行聯(lián)合使用時(shí)。
- 當(dāng)你提供一個(gè)產(chǎn)品庫(kù)轻腺,而只想顯示它們的接口而不是實(shí)現(xiàn)時(shí)乐疆。
角色:
- 抽象工廠角色
抽象工廠模式的核心,包含對(duì)多個(gè)產(chǎn)品結(jié)構(gòu)的申明贬养,任何工廠類都必須實(shí)現(xiàn)這個(gè)接口挤土。
- 具體工廠角色
具體工廠角色類是抽象工廠的一個(gè)實(shí)現(xiàn)負(fù)責(zé)實(shí)例化某個(gè)產(chǎn)品族的產(chǎn)品對(duì)象。 - 抽象角色
抽象模式所創(chuàng)建的所有對(duì)象的父類煤蚌,它負(fù)責(zé)描述所有實(shí)例所共有的公共接口 - 具體產(chǎn)品角色
抽象模式所創(chuàng)建的具體實(shí)例對(duì)象
抽象工廠方法對(duì)應(yīng)產(chǎn)品結(jié)構(gòu)耕挨,具體工廠對(duì)應(yīng)產(chǎn)品族。
//抽象工廠角色
public interface FruitFactory {
//實(shí)例化蘋果
public Fruit getApple();
//實(shí)例化Banana
public Fruit getBanana();
}
//具體工廠角色
public class NorthFruitFactory implements FruitFactory {
@Override
public Fruit getApple() {
return new NorthApple();
}
@Override
public Fruit getBanana() {
return new NorthBanana();
}
}
//具體工廠角色
public class SouthFruitFactory implements FruitFactory {
@Override
public Fruit getApple() {
return new SouthApple();
}
@Override
public Fruit getBanana() {
return new SouthBanana();
}
}
//抽象角色
public interface Fruit {
public void get();
}
//抽象角色
public abstract class Apple implements Fruit{
public abstract void get();
}
//抽象角色
public abstract class Banana implements Fruit{
public abstract void get();
}
//具體產(chǎn)品角色
public class NorthApple extends Apple{
@Override
public void get() {
System.out.println("采集北方蘋果");
}
}
//具體產(chǎn)品角色
public class NorthBanana extends Banana{
@Override
public void get() {
System.out.println("采集北方香蕉");
}
}
//具體產(chǎn)品角色
public class SouthApple extends Apple{
@Override
public void get() {
System.out.println("采集南方蘋果");
}
}
//具體產(chǎn)品角色
public class SouthBanana extends Banana{
@Override
public void get() {
System.out.println("采集南方香蕉");
}
}
//測(cè)試方法
public class Main {
public static void main(String[] args) {
NorthFruitFactory northFruitFactory = new NorthFruitFactory();
Fruit northApple = northFruitFactory.getApple();
northApple.get();
Fruit northBanana = northFruitFactory.getBanana();
northBanana.get();
System.out.println("**********");
SouthFruitFactory southFruitFactory = new SouthFruitFactory();
Fruit southApple = southFruitFactory.getApple();
southApple.get();
Fruit southBanana = southFruitFactory.getBanana();
southBanana.get();
}
}
如果要新增的話尉桩,我們只需要添加一個(gè)產(chǎn)品鏈
比如我們?nèi)绻€有一個(gè)溫室蘋果和溫室香蕉的話筒占,需要新增以下類:
GreenhouseApple.java
GreenhouseBanana.java
GreenhouseFruitFactory.java
這樣既可新增一個(gè)產(chǎn)品鏈。
但是如果需要添加一個(gè)新的產(chǎn)品蜘犁,那么我們必須修改所有的工廠方法翰苫,新增get方法。
四、 單例模式(Singleton)
單例模式是一種對(duì)象創(chuàng)建型模式奏窑,使用單例模式导披,可以保證為一個(gè)類只生成唯一的實(shí)例對(duì)象。也就是說埃唯,在整個(gè)程序空間中撩匕,該類只存在一個(gè)實(shí)例對(duì)象。
定義:
保證一個(gè)類墨叛、只有一個(gè)實(shí)例存在止毕,同時(shí)提供能對(duì)該實(shí)例加以訪問的全局訪問方法。
適用性:
- 當(dāng)類只能有一個(gè)實(shí)例而且客戶可以從一個(gè)眾所周知的訪問點(diǎn)訪問它時(shí)漠趁。
- 當(dāng)這個(gè)唯一實(shí)例應(yīng)該是通過子類化可擴(kuò)展的扁凛,并且客戶應(yīng)該無(wú)需更改代碼就能實(shí)現(xiàn)一個(gè)擴(kuò)展的實(shí)例時(shí)。
1. 餓漢式
public class Person {
public static final Person person = new Person();
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構(gòu)造函數(shù)私有化
private Person(){}
//提供一個(gè)全局的靜態(tài)方法
public static Person getPerson(){
return person;
}
}
//測(cè)試函數(shù)
public class Main {
public static void main(String[] args) {
Person person_1 = Person.getPerson();
System.out.println(person_1.hashCode());
Person person_2 = Person.getPerson();
System.out.println(person_2.hashCode());
}
}
2. 懶漢式(非線程安全)
public class Person2 {
private static Person2 person;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構(gòu)造函數(shù)私有化
private Person2(){}
//提供一個(gè)全局的靜態(tài)方法
public static Person2 getPerson(){
if(person == null){
person = new Person2();
}
return person;
}
}
測(cè)試函數(shù)同上
3.雙重檢查(線程安全)
public class Person3 {
private static Person3 person;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//構(gòu)造函數(shù)私有化
private Person3(){}
//提供一個(gè)全局的靜態(tài)方法
public static Person3 getPerson(){
if(person == null){
synchronized (Person3.class){
if(person == null){
person = new Person3();
}
}
}
return person;
}
}
測(cè)試方法同上
五闯传、 原型模式(Prototype)
原型模式是一種對(duì)象創(chuàng)建型模式谨朝,它采用復(fù)制原型對(duì)象的方法來創(chuàng)建對(duì)象的實(shí)例。使用原型模式創(chuàng)建的實(shí)例甥绿,具有與原型一樣的數(shù)據(jù)字币。
- 由原型對(duì)象自身創(chuàng)建目標(biāo)對(duì)象,也就是說妹窖,對(duì)象創(chuàng)建這一動(dòng)作發(fā)自原型對(duì)象本身纬朝。
- 目標(biāo)對(duì)象是原型對(duì)象的一個(gè)克隆。也就是說骄呼,通過原型對(duì)象模式創(chuàng)建的對(duì)象共苛,不僅僅與原型對(duì)象具有相同的結(jié)構(gòu),還與原型對(duì)象具有相同的值蜓萄。
- 根據(jù)對(duì)象克隆深度層次的不同隅茎,有淺度克隆與深度克隆。
適用性:
當(dāng)要實(shí)例化的類實(shí)在運(yùn)行時(shí)刻指定時(shí)嫉沽,例如通過動(dòng)態(tài)裝載辟犀;或者為了避免創(chuàng)建一個(gè)與產(chǎn)品類層次平行的工廠類層次是;或者當(dāng)一個(gè)類的實(shí)例只能有幾種不同狀態(tài)中的一種時(shí)绸硕。建立相應(yīng)數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實(shí)例化該類更方便一些堂竟。
實(shí)現(xiàn)方法:
- 實(shí)現(xiàn)Cloneable接口
- 編寫clone方法
代碼演示:
public class Person implements Cloneable{
private String name;
private int age;
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
//測(cè)試函數(shù)
public class Main {
public static void main(String[] args) {
Person person1 = new Person();
person1.setName("王小二");
person1.setAge(23);
person1.setSex("男");
Person person2 = person1;
Person person3 = person1.clone();
System.out.println("person1:" + person1.hashCode() + " " +
person1.getName() + " " + person1.getAge() + " " + person1.getSex());
System.out.println("person2:" + person2.hashCode() + " " +
person2.getName() + " " + person2.getAge() + " " + person2.getSex());
System.out.println("person3:" + person3.hashCode() + " " +
person3.getName() + " " + person3.getAge() + " " + person3.getSex());
}
}
運(yùn)行結(jié)果:
person1:705927765 王小二 23 男
person2:705927765 王小二 23 男
person3:366712642 王小二 23 男
淺度克隆:如果Person中的某個(gè)屬性是一個(gè)引用值的話玻佩,淺度克隆不會(huì)克隆這個(gè)引用對(duì)象出嘹。
深度克隆:克隆Person中所有的對(duì)象咬崔。
以上是淺度克隆税稼,如果要使用深度克隆烦秩,可以手動(dòng)在clone中復(fù)制引用對(duì)象完成深度克隆。
六郎仆、 建造者模式(Builder)
建造者模式也稱生成器模式只祠,是一種對(duì)象創(chuàng)建型模式之一,用來隱藏復(fù)合對(duì)象的創(chuàng)建過程扰肌,它把復(fù)合對(duì)象的創(chuàng)建過程加以抽象抛寝,通過子類繼承和重載的方式,動(dòng)態(tài)的創(chuàng)建具有復(fù)合屬性的對(duì)象曙旭。
意圖:
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與他的表示分離墩剖,是的同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
適用性:
- 當(dāng)創(chuàng)建復(fù)雜對(duì)象的算法應(yīng)該獨(dú)立于該對(duì)象的組成部分以及它們的裝配方式時(shí)夷狰。
- 當(dāng)構(gòu)造過程必須允許被構(gòu)造的對(duì)象有不同的表示時(shí)。
代碼示例:
//
public class House {
//底板
private String floor;
//墻
private String wall;
//屋頂
private String housetop;
//省略get郊霎、set方法
}
//施工隊(duì)接口
public interface HouseBuilder {
//修地板
public void makeFloor();
//修墻
public void makeWall();
//修屋頂
public void makeHousetop();;
public House getHouse();
}
//具體施工隊(duì)
public class PingFangBuilder implements HouseBuilder {
House house = new House();
@Override
public void makeFloor() {
house.setFloor("平方--->地板");
}
@Override
public void makeWall() {
house.setWall("平方--->墻");
}
@Override
public void makeHousetop() {
house.setHousetop("平方--->房頂");
}
@Override
public House getHouse() {
return house;
}
}
//設(shè)計(jì)者
public class HouseDicretor {
private HouseBuilder builder;
public HouseDicretor(HouseBuilder builder) {
this.builder = builder;
}
public void makeHouse(){
builder.makeFloor();
builder.makeWall();
builder.makeHousetop();
}
}
//測(cè)試方法
public class Main {
public static void main(String[] args) {
//客戶直接造房子
House house = new House();
house.setWall("墻");
house.setFloor("底板");
house.setHousetop("屋頂");
//由工程隊(duì)來修
HouseBuilder builder = new PingFangBuilder();
//設(shè)計(jì)者來做
HouseDicretor dicretor = new HouseDicretor(builder);
dicretor.makeHouse();
House pingfangHouse = builder.getHouse();
System.out.println(pingfangHouse.getFloor());
System.out.println(pingfangHouse.getWall());
System.out.println(pingfangHouse.getHousetop());
}
}
八沼头、 裝飾模式(Decorator)
裝飾模式又叫包裝模式。通過一種對(duì)客戶端透明的方式來擴(kuò)展對(duì)象的功能书劝,是繼承關(guān)系的一個(gè)替換方案进倍。
角色:
- 抽象組件角色: 一個(gè)抽象接口,是被裝飾類和裝飾類的父接口购对。
- 具體組件角色:為抽象組件的實(shí)現(xiàn)類猾昆。
- 抽象裝飾角色:包含一個(gè)組件的引用,并定義了與抽象組件一致的接口骡苞。
- 具體裝飾角色:為抽象裝飾角色的實(shí)現(xiàn)類垂蜗。負(fù)責(zé)具體的裝飾。
意圖:
動(dòng)態(tài)的給一個(gè)對(duì)象添加一些額外的職責(zé)解幽。
適用性:
- 在不影響其他對(duì)象的情況下贴见,以動(dòng)態(tài)、透明的方式給單個(gè)對(duì)象添加職責(zé)躲株。
- 處理那些可以撤銷的職責(zé)
- 當(dāng)不能采用生成子類的方法進(jìn)行擴(kuò)充時(shí)片部,一種情況是可能有大量獨(dú)立的擴(kuò)展,為支持每一種組合將產(chǎn)生大量的子類霜定,使得子類數(shù)目呈爆炸性增長(zhǎng)档悠。另一種情況是可能是因?yàn)轭惗x被隱藏,或類定義不能用于生成子類望浩。
代碼演示:
//抽象組件角色
public interface Car {
public void show();
public void run();
}
//具體組件角色
public class RunCar implements Car {
@Override
public void show() {
this.run();
}
@Override
public void run() {
System.out.println("可以跑");
}
}
//抽象裝飾角色
public abstract class CarDecorator implements Car{
private Car car;
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public CarDecorator(Car car) {
this.car = car;
}
public abstract void show();
}
//具體裝飾角色
public class FlyCarDecorator extends CarDecorator {
public FlyCarDecorator(Car car) {
super(car);
}
@Override
public void run() {
}
@Override
public void show() {
this.getCar().show();
this.fly();
}
public void fly(){
System.out.println("可以飛");
}
}
//具體裝飾角色
public class SwimCarDecorator extends CarDecorator {
public SwimCarDecorator(Car car) {
super(car);
}
@Override
public void run() {
}
@Override
public void show() {
this.getCar().show();
this.swim();
}
public void swim() {
System.out.println("可以游");
}
}
//測(cè)試類
public class Main {
public static void main(String[] args) {
Car runCar = new RunCar();
CarDecorator flyCar = new FlyCarDecorator(runCar);
CarDecorator swimCar = new SwimCarDecorator(flyCar);
swimCar.show();
}
}
運(yùn)行結(jié)果:
可以跑
可以飛
可以游
九辖所、 策略模式(Strategy)
策略模式也是行為模式的一種,它對(duì)一系列算法加以封裝曾雕,為所有算法定義一個(gè)抽象的接口奴烙,并通過繼承該抽象算法接口對(duì)所有的算法加以封裝和實(shí)現(xiàn),具體的算法選擇交由客戶端決定。
角色:
- Strategy:策略(算法)抽象切诀。
- ConcreteStrategy:各種策略(算法)的具體實(shí)現(xiàn)揩环。
- Context:策略的外部封裝類,或者說策略的容器類幅虑。根據(jù)不同策略執(zhí)行不同的行為丰滑。策略由外部環(huán)境決定。
適用性:
- 許多相關(guān)類僅僅是行為有異倒庵““策略”提供一種用多個(gè)行為中的一個(gè)行為來配置一個(gè)類的方法。
- 需要使用一個(gè)算法的不同變體擎宝。例如郁妈,你可能會(huì)定義一些反應(yīng)不同的空間/時(shí)間權(quán)衡的算法。當(dāng)這些變體實(shí)現(xiàn)為一個(gè)算法的類層次是绍申,可以使用策略模式噩咪。
- 算法使用客戶不應(yīng)該知道的數(shù)據(jù),可以使用策略模式以避免暴露復(fù)雜的极阅,預(yù)算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)胃碾。
- 一個(gè)類定義了多種行為,并且這些行為在這個(gè)類的操作中以多個(gè)條件語(yǔ)句的形式出現(xiàn)筋搏,將相關(guān)的條件分支一如它們各自的策略類中一代替這些條件語(yǔ)句仆百。
代碼展示:
//算法抽象
public interface Transition {
public String transition(String str);
}
//算法實(shí)現(xiàn)(轉(zhuǎn)換為大寫字母)
public class UpperCaseTransition implements Transition{
@Override
public String transition(String str) {
return str.toUpperCase();
}
}
//算法實(shí)現(xiàn)(轉(zhuǎn)換為小寫字母)
public class LowerCaseTransition implements Transition {
@Override
public String transition(String str) {
return str.toLowerCase();
}
}
//策略的外部封裝
public class Context implements Transition {
private Transition transition;
public Context(Transition transition) {
this.transition = transition;
}
@Override
public String transition(String str) {
return transition.transition(str);
}
}
//測(cè)試類
public class Main {
public static void main(String[] args) {
Context context = new Context(new UpperCaseTransition());
System.out.println(context.transition("abcdef"));
Context context_1 = new Context(new LowerCaseTransition());
System.out.println(context_1.transition("ABCDEF"));
}
}
運(yùn)行結(jié)果:
ABCDEF
abcdef
策略模式的優(yōu)點(diǎn):
- 策略模式提供了管理相關(guān)的算法族的辦法。策略類的等級(jí)結(jié)構(gòu)定義了一個(gè)算法或行為族奔脐。恰當(dāng)使用繼承可以把公共的代碼移到父類里面俄周,從而避免重復(fù)的代碼。
- 策略模式提供了可以替換繼承關(guān)系的辦法髓迎。繼承可以處理多種算法或行為栈源。如果不是用策略模式,那么使用算法或行為的環(huán)境類就可能會(huì)有一些子類竖般,每一個(gè)子類提供一個(gè)不同的算法或行為甚垦。但是,這樣一來算法或行為的使用者就和算法或行為本身混在一起涣雕。決定使用哪一種算法或采取哪一種行為的邏輯就和算法或行為的邏輯混合在一起艰亮,從而不可能再獨(dú)立演化。繼承使得動(dòng)態(tài)改變算法或
行為變得不可能挣郭。 - 使用策略模式可以避免使用多重條件轉(zhuǎn)移語(yǔ)句迄埃。多重轉(zhuǎn)移語(yǔ)句不易維護(hù),它把采取哪一種算法或采取哪一種行為的邏輯與算法或行為的邏輯混合在一起兑障,統(tǒng)統(tǒng)列在一個(gè)多重轉(zhuǎn)移語(yǔ)句里面侄非,比使用繼承的辦
法還要原始和落后蕉汪。
缺點(diǎn):
- 客戶端必須知道所有的策略類,并自行決定使用哪一個(gè)策略類逞怨。這就意味著客戶端必須理解這些算法的區(qū)別者疤,以便適時(shí)選擇恰當(dāng)?shù)乃惴悺Q言之叠赦,策略模式只適用于客戶端知道所有的算法或行為的情況驹马。
- 策略模式造成很多的策略類。有時(shí)候可以通過把依賴于環(huán)境的狀態(tài)保存到客戶端里面除秀,而將策略類設(shè)計(jì)成可共享的糯累,這樣策略類實(shí)例可以被不同客戶端使用。換言之册踩,可以使用享元模式來減少對(duì)象的數(shù)量泳姐。
十、觀察者模式(Observer)
觀察者模式是行為模式之一暂吉,它的作用是當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí)仗岸,能夠自動(dòng)通知其他關(guān)聯(lián)對(duì)象,自動(dòng)刷新對(duì)象狀態(tài)借笙。
觀察者模式提供給關(guān)聯(lián)對(duì)象一種同步通信的手段,是某個(gè)對(duì)象與依賴它的其他對(duì)象之間保持狀態(tài)同步较锡。
角色:
- Subject(被觀察者):被觀察的對(duì)象业稼。當(dāng)需要被觀察的狀態(tài)發(fā)生變化時(shí),需要通知隊(duì)列中所有觀察者對(duì)象蚂蕴。Subject需要維持(添加低散,刪除,通知)一個(gè)觀察者對(duì)象的隊(duì)列列表骡楼。
- ConcreteSubject:被觀察者的具體實(shí)現(xiàn)熔号。包含一些基本的屬性狀態(tài)及其他操作。
- Observer(觀察者):接口或抽象類鸟整。當(dāng)Subject的狀態(tài)發(fā)生變化時(shí)引镊,Observer對(duì)象將通過一個(gè)callback函數(shù)得到通知。
- ConcreteObserver:觀察者的具體實(shí)現(xiàn)篮条。得到通知后將完成一些具體的業(yè)務(wù)邏輯處理弟头。
代碼示例:
//被觀察者
public class Person extends Observable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
this.setChanged();
this.notifyObservers();
}
}
//觀察者
public class MyObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("對(duì)象發(fā)生變化");
}
}
//測(cè)試函數(shù)
public class Main {
public static void main(String[] args) {
Person person = new Person();
//注冊(cè)觀察者
person.addObserver(new MyObserver());
person.setName("王二小");
}
}
觀察者模式典型應(yīng)用:
- 偵聽時(shí)間驅(qū)動(dòng)程序設(shè)計(jì)中的外部事件
- 偵聽/件事某個(gè)對(duì)象的狀態(tài)變化
- 發(fā)布者/訂閱者(publicsher/subscriber)模型中,當(dāng)一個(gè)外部事件被觸發(fā)是涉茧,通知列表中的訂閱者赴恨。
適用性:
- 當(dāng)一個(gè)抽象模型有兩個(gè)方面,其中一個(gè)方面依賴于另一個(gè)方面伴栓,將這兩者封裝在獨(dú)立的對(duì)象中以使它們可以獨(dú)立地改變和復(fù)用伦连。
- 當(dāng)對(duì)一個(gè)對(duì)象那個(gè)的改變需要同時(shí)改變其他對(duì)象雨饺,而不知道具體對(duì)象有待改變,
- 當(dāng)一個(gè)對(duì)象必須通知其他對(duì)象惑淳,而它又不能假定其他對(duì)象是誰(shuí)额港。換言之,你不希望這些對(duì)象是緊密耦合的汛聚。
十一锹安、 享元模式(Flyweight)
享元模式是構(gòu)造型模式之一,它通過與其他類似對(duì)象共享數(shù)據(jù)來減小內(nèi)存占用倚舀。
角色:
- 抽象享元角色: 所有具體享元類的父類叹哭,規(guī)定一些需要實(shí)現(xiàn)的公共接口。
- 具體享元角色: 抽象享元角色的具體實(shí)現(xiàn)類痕貌,并實(shí)現(xiàn)了抽象享元角色規(guī)定的方法风罩。
- 享元工廠角色: 負(fù)責(zé)創(chuàng)建和管理享元角色。
適用性:
- 一個(gè)程序使用的大量的對(duì)象舵稠。
- 完全由于使用大量對(duì)象超升,造成很大的存儲(chǔ)開銷。
- 對(duì)象的大多數(shù)狀態(tài)都可以變?yōu)橥獠繝顟B(tài)哺徊。
代碼示例:
(本例中沒有抽象享元角色)
//具體享元角色
public class MyCharacter {
private char mychar;
public MyCharacter(char mychar ) {
this.mychar = mychar;
}
public void display(){
System.out.println(mychar);
}
}
//享元工廠角色
public class MyCharacterFactory {
private Map<Character,MyCharacter> pool;
public MyCharacterFactory() {
pool = new HashMap<Character,MyCharacter>();
}
//享元模式核心內(nèi)容
public MyCharacter getMyCharacter(Character character){
MyCharacter mychar = pool.get(character);
if(mychar == null){
mychar = new MyCharacter(character);
pool.put(character, mychar);
}
return mychar;
}
}
//測(cè)試函數(shù)
public class Main {
public static void main(String[] args) {
//創(chuàng)建工廠
MyCharacterFactory mcf = new MyCharacterFactory();
//從工廠中取出
MyCharacter myChar1 = mcf.getMyCharacter('a');
MyCharacter myChar2 = mcf.getMyCharacter('b');
MyCharacter myChar3 = mcf.getMyCharacter('a');
myChar1.display();
myChar2.display();
myChar3.display();
System.out.println(myChar1.hashCode() + " " + myChar2.hashCode() + " " + myChar3.hashCode());
}
}
運(yùn)行結(jié)果:(結(jié)果說明我們創(chuàng)建的myChar1和myChar3是同一個(gè)對(duì)象)
a
b
a
705927765 366712642 705927765
十二室琢、 代理模式(proxy)
代理模式是構(gòu)造性的是耳機(jī)模式之一,它可以為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的一種訪問落追。
所謂代理盈滴,是指具有與代理元(被代理的對(duì)象)具有相同的接口的類,客戶端必須通過代理與被代理的目標(biāo)類交互轿钠,而代理一般在交互的過程中(交互前后)巢钓,進(jìn)行某些特別的處理。
角色:
- subject(抽象主題角色):真實(shí)主題與代理主題的共同接口疗垛。
- RealSubject(真實(shí)主題角色):定義了代理角色所代表的真實(shí)對(duì)象症汹。
- Proxy(代理主題角色):含有對(duì)真實(shí)主題角色的引用,代理角色通常在將客戶端調(diào)用傳遞給真實(shí)主題對(duì)象之前或者之后執(zhí)行某些操作贷腕,而不是單純返回真實(shí)的對(duì)象背镇。
適用性:
在需要用比較通用和復(fù)雜的對(duì)象指針代替簡(jiǎn)單的指針的時(shí)候,使用Proxy模式泽裳,下面是一些可以使用Proxy模式常見情況:
- 遠(yuǎn)程代理(Remote Proxy)為一個(gè)對(duì)象在不同的地址空間提供局部代表
代碼演示:
//抽象主題角色:
public interface Subject {
public void sailBook();
}
//真實(shí)主題角色
public class RealSubject implements Subject {
@Override
public void sailBook() {
System.out.println("買書");
}
}
//代理主題角色
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
public void Discount(){
System.out.println("打折");
}
public void Vouchers(){
System.out.println("贈(zèng)送代金券");
}
@Override
public void sailBook() {
this.Discount();
if(this.realSubject == null){
realSubject = new RealSubject();
}
realSubject.sailBook();
this.Vouchers();
}
}
//測(cè)試函數(shù)
public class Main {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxySubject ps = new ProxySubject(realSubject);
ps.sailBook();
}
}
運(yùn)行結(jié)果:
打折
買書
贈(zèng)送代金券
動(dòng)態(tài)代理
代碼示例:
//抽象主題角色:
public interface Subject {
public void sailBook();
}
//真實(shí)主題角色
public class RealSubject implements Subject {
@Override
public void sailBook() {
System.out.println("買書");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyHandler implements InvocationHandler {
private RealSubject realSubject;
public void setRealSubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
public void Discount(){
System.out.println("打折");
}
public void Vouchers(){
System.out.println("贈(zèng)送代金券");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
Discount();
result = method.invoke(realSubject, args);
Vouchers();
return result;
}
}
//測(cè)試函數(shù)
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
MyHandler myHandler = new MyHandler();
myHandler.setRealSubject(realSubject);
Subject proxySubject =
(Subject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
realSubject.getClass().getInterfaces(), myHandler);
proxySubject.sailBook();
}
}
十三芽世、 外觀模式(Facade)
外觀模式為一組具有類似功能的類群,比如類庫(kù)诡壁、子系統(tǒng)等等济瓢,提供一個(gè)一致的簡(jiǎn)單界面,這個(gè)一致的簡(jiǎn)單界面被稱作facade妹卿。
適用性:
當(dāng)你要為一個(gè)復(fù)雜子系統(tǒng)提供一個(gè)簡(jiǎn)單接口時(shí)旺矾。子系統(tǒng)往往因?yàn)椴粩嘌莼兊靡瞾碓綇?fù)雜蔑鹦。大多數(shù)模式使用時(shí)都會(huì)產(chǎn)生更多更小的類,這使得子系統(tǒng)更具有可重用性箕宙,也跟你容易對(duì)子系統(tǒng)進(jìn)行定制嚎朽,但這也給那些不需要定制子系統(tǒng)的用戶帶來了一些使用上的困難。Facade可以提供一個(gè)簡(jiǎn)單的缺省視圖柬帕,這一視圖對(duì)大多數(shù)用戶來說已經(jīng)足夠哟忍,而那些需要更多的可定制性的用戶可以越過facade層。
客戶程序與抽象類的和實(shí)現(xiàn)部分之間存在很大的依賴性陷寝。引入facade將這個(gè)子系統(tǒng)與客戶以及其他的子系統(tǒng)分離锅很,可以提高子系統(tǒng)的獨(dú)立性和可移植性。當(dāng)你需要構(gòu)建一個(gè)層次結(jié)構(gòu)的子系統(tǒng)時(shí)凤跑,使用facade模式定義子系統(tǒng)中每層的入口點(diǎn)爆安。如果子系統(tǒng)之間相互依賴的,你可以讓它們僅通過facade進(jìn)行通訊仔引,從而簡(jiǎn)化它們之間的依賴關(guān)系扔仓。
角色:
- Facade:為調(diào)用方定義簡(jiǎn)單的調(diào)用接口。
- Clients:調(diào)用者咖耘。通過Facade接口調(diào)用提供某功能的內(nèi)部類群翘簇。
- Packages:功能提供者,指提供功能的類群儿倒、模塊版保、或者子系統(tǒng)。
代碼示例:
//功能提供者
public class SystemA {
/**
* A子系統(tǒng)實(shí)現(xiàn)功能
*/
public void doSomething(){
System.out.println("實(shí)現(xiàn)A子系統(tǒng)功能");
}
}
//功能提供者
public class SystemB {
/**
* B子系統(tǒng)實(shí)現(xiàn)功能
*/
public void doSomething(){
System.out.println("實(shí)現(xiàn)B子系統(tǒng)功能");
}
}
//Facade
public class Facade {
private SystemA systemA;
private SystemB systemB;
public Facade() {
systemA = new SystemA();
systemB = new SystemB();
}
public void doSomething(){
this.systemA.doSomething();
this.systemB.doSomething();
}
}
//測(cè)試函數(shù)
public class Main {
public static void main(String[] args) {
//常規(guī)方法
//實(shí)現(xiàn)A子系統(tǒng)功能
SystemA systemA = new SystemA();
systemA.doSomething();
//實(shí)現(xiàn)B子系統(tǒng)功能
SystemB systemB = new SystemB();
systemB.doSomething();
//外觀模式
Facade facade = new Facade();
facade.doSomething();
}
}