一猪叙、什么是設(shè)計(jì)模式
- 設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用赘风、多數(shù)人知曉的夹囚、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)邀窃。使用設(shè)計(jì)模式是為了可重用代碼荸哟、讓代碼更容易被他人理解、保證代碼可靠性瞬捕。 毫無疑問鞍历,設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的,設(shè)計(jì)模式使代碼編制真正工程化肪虎,設(shè)計(jì)模式是軟件工程的基石劣砍,如同大廈的一塊塊磚石一樣。項(xiàng)目中合理的運(yùn)用設(shè)計(jì)模式可以完美的解決很多問題扇救,每種模式在現(xiàn)在中都有相應(yīng)的原理來與之對(duì)應(yīng)刑枝,每一個(gè)模式描述了一個(gè)在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的核心解決方案爵政,這也是它能被廣泛應(yīng)用的原因
二仅讽、為什么學(xué)習(xí)設(shè)計(jì)模式
- 它是很多人很多年以來的經(jīng)驗(yàn)智慧的總結(jié),教你怎樣更高效的來玩耍代碼钾挟,使原來單一的代碼模式變得有趣洁灵,漂亮。他是使編程藝術(shù)化的入門掺出。
三徽千、常見的面向?qū)ο笤O(shè)計(jì)原則
1、迪米特法則汤锨,又稱最少知道原則(Demeter Principle)
- 最少知道原則是指:一個(gè)實(shí)體應(yīng)當(dāng)盡量少地與其他實(shí)體之間發(fā)生相互作用双抽,使得系統(tǒng)功能模塊相對(duì)獨(dú)立。
從依賴者的角度來說闲礼,只依賴應(yīng)該依賴的對(duì)象牍汹。
從被依賴者的角度說铐维,只暴露應(yīng)該暴露的方法。降低耦合
假設(shè)類A實(shí)現(xiàn)了某個(gè)功能慎菲,類B需要調(diào)用類A的去執(zhí)行這個(gè)功能嫁蛇,那么類A應(yīng)該只暴露一個(gè)函數(shù)給類B,這個(gè)函數(shù)表示是實(shí)現(xiàn)這個(gè)功能的函數(shù)露该,而不是讓類A把實(shí)現(xiàn)這個(gè)功能的所有細(xì)分的函數(shù)暴露給B睬棚。
2、里氏代換原則
- 基類和子類之間的關(guān)系解幼。子類可以擴(kuò)展父類的功能抑党,但不能改變父類原有的功能。也就是說:子類繼承父類時(shí)撵摆,除添加新的方法完成新增功能外底靠,盡量不要重寫父類的方法。
關(guān)于里氏替換原則的例子特铝,最有名的是“正方形不是長方形”苛骨。當(dāng)然,生活中也有很多類似的例子苟呐,例如,企鵝俐筋、鴕鳥和幾維鳥從生物學(xué)的角度來劃分牵素,它們屬于鳥類;但從類的繼承關(guān)系來看澄者,由于它們不能繼承“鳥”會(huì)飛的功能笆呆,所以它們不能定義成“鳥”的子類。同樣粱挡,由于“氣球魚”不會(huì)游泳赠幕,所以不能定義成“魚”的子類;“玩具炮”炸不了敵人询筏,所以不能定義成“炮”的子類等榕堰。
3、依賴倒轉(zhuǎn)原則(Dependence Inversion Principle)
它降低了客戶與實(shí)現(xiàn)模塊之間的耦合嫌套。
由于在軟件設(shè)計(jì)中逆屡,細(xì)節(jié)具有多變性,而抽象層則相對(duì)穩(wěn)定踱讨,因此以抽象為基礎(chǔ)搭建起來的架構(gòu)要比以細(xì)節(jié)為基礎(chǔ)搭建起來的架構(gòu)要穩(wěn)定得多魏蔗。這里的抽象指的是接口或者抽象類,而細(xì)節(jié)是指具體的實(shí)現(xiàn)類痹筛。
使用接口或者抽象類的目的是制定好規(guī)范和契約莺治,而不去涉及任何具體的操作廓鞠,把展現(xiàn)細(xì)節(jié)的任務(wù)交給它們的實(shí)現(xiàn)類去完成。
比如常見的參數(shù)里傳的是父類谣旁,而不是具體類床佳,比如一個(gè)售賣功能里面的參數(shù)是商店,商店有可能是北京商店蔓挖,也可能是上海商店夕土,所以這個(gè)號(hào)參數(shù)要使用商店這個(gè)類而不是具體的某個(gè)商店
4、接口隔離原則(Interface Segregation Principle)
- 這個(gè)原則的意思是:使用多個(gè)隔離的接口瘟判,比使用單個(gè)接口要好怨绣。它還有另外一個(gè)意思是:降低類之間的耦合度。由此可見拷获,其實(shí)設(shè)計(jì)模式就是從大型軟件架構(gòu)出發(fā)篮撑、便于升級(jí)和維護(hù)的軟件設(shè)計(jì)思想,它強(qiáng)調(diào)降低依賴匆瓜,降低耦合赢笨。以下這里例子一眼就能對(duì)比出接口隔離的好處了
public interface UserService {
public void login(String username, String password);
public void register(String email, String username, String password);
public void logError(String msg);
public void sendEmail(String email);
}
5、開閉原則(Open Close Principle)
- 開閉原則的意思是:對(duì)擴(kuò)展開放驮吱,對(duì)修改關(guān)閉茧妒。
在程序需要進(jìn)行拓展的時(shí)候,不能去修改原有的代碼左冬,實(shí)現(xiàn)一個(gè)熱插拔的效果桐筏。簡言之,是為了使程序的擴(kuò)展性好拇砰,易于維護(hù)和升級(jí)梅忌。想要達(dá)到這樣的效果,我們需要使用接口和抽象類除破,后面的具體設(shè)計(jì)中我們會(huì)提到這點(diǎn)牧氮。
6、單一原則(Composite Reuse Principle)
- 一個(gè)類單一職責(zé)瑰枫,防止耦合
四踱葛、設(shè)計(jì)模式分類
如下圖所示:
創(chuàng)建型模式
這些設(shè)計(jì)模式提供了一種在創(chuàng)建對(duì)象的同時(shí)隱藏創(chuàng)建邏輯的方式,而不是使用新的運(yùn)算符直接實(shí)例化對(duì)象光坝。這使得程序在判斷針對(duì)某個(gè)給定實(shí)例需要?jiǎng)?chuàng)建哪些對(duì)象時(shí)更加靈活剖毯。
public class ShapeFactory {
//普通工廠模式教馆,不符合開閉原則
public Shape getShape(String shapeType){
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
抽象工廠更符合開-閉原則逊谋,降低耦合,但抽象工廠模式很難支持新種類產(chǎn)品的變化土铺。類復(fù)雜胶滋。實(shí)際應(yīng)用中使用簡單工廠多點(diǎn)
public class Singleton {
//餓漢模式板鬓,簡單,線程安全究恤,效率高俭令,但一開始就加載了,容易產(chǎn)生垃圾
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
- 建造者模式 (Builder Pattern):將一個(gè)復(fù)雜的構(gòu)建過程與其具表示細(xì)節(jié)相分離部宿,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示
public class User {
private final String firstName; // 必傳參數(shù)
private final String lastName; // 必傳參數(shù)
private final int age; // 可選參數(shù)
private final String phone; // 可選參數(shù)
private final String address; // 可選參數(shù)
private User(UserBuilder builder) {
this.firstName = builder.firstName;
this.lastName = builder.lastName;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
public String getPhone() {
return phone;
}
public String getAddress() {
return address;
}
public static class UserBuilder {
private final String firstName;
private final String lastName;
private int age;
private String phone;
private String address;
public UserBuilder(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public UserBuilder phone(String phone) {
this.phone = phone;
return this;
}
public UserBuilder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
}
調(diào)用
new User.UserBuilder("王", "小二")
.age(20)
.phone("123456789")
.address("亞特蘭蒂斯大陸")
.build();
- 原型模式 (Prototype Pattern):通過拷貝原型創(chuàng)建新的對(duì)象抄腔,當(dāng)我們的類初始化需要消耗很多的資源時(shí),就可以使用原型模式理张,因?yàn)槲覀兊目寺〔粫?huì)執(zhí)行構(gòu)造方法赫蛇,避免了初始化占有的時(shí)間和空間。
1雾叭、淺克隆:
對(duì)于數(shù)據(jù)類型是基本數(shù)據(jù)類型的成員變量悟耘,淺拷貝會(huì)直接進(jìn)行值傳遞,也就是將該屬性值復(fù)制一份給新的對(duì)象织狐。
對(duì)于數(shù)據(jù)類型是引用數(shù)據(jù)類型的成員變量暂幼,比如說成員變量是某個(gè)數(shù)組,某個(gè)類型的對(duì)象等移迫,那么淺拷貝會(huì)進(jìn)行引用傳遞旺嬉,也就是只是該成員變量的引用值(內(nèi)存地址)復(fù)制一份給新的對(duì)象,因?yàn)閷?shí)際上兩個(gè)對(duì)象的該成員變量都指向同一個(gè)實(shí)例厨埋,在這種情況下鹰服,在一個(gè)對(duì)象中修改該成員變量會(huì)影響到另一個(gè)對(duì)象的該成員變量值。
//這里不實(shí)現(xiàn)Serializable接口也可以實(shí)現(xiàn)淺克隆
public class User implements Cloneable,Serializable{
private String name;
private Date birth;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 實(shí)現(xiàn)克隆的方法
*/
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
//使用
Date date = new Date(1231231231231l);
User user = new User();
user.setName("波波烤鴨");
user.setAge(18);
user.setBirth(date);
System.out.println("----輸出原型對(duì)象的屬性------");
System.out.println(user);
System.out.println(user.getName());
System.out.println(user.getBirth());
// 克隆對(duì)象
User user1 =(User) user.clone();
// 修改原型對(duì)象中的屬性
date.setTime(123231231231l);
System.out.println(user.getBirth());
// 修改參數(shù)
user1.setName("dpb");
System.out.println("-------克隆對(duì)象的屬性-----");
System.out.println(user1);
System.out.println(user1.getName());
System.out.println(user1.getBirth());
//打印如下
----輸出原型對(duì)象的屬性-----
com.dpb.prototype.User@15db9742
波波烤鴨
Tue Jan 06 16:40:31 CST 2009 # 1
Tue Nov 27 14:53:51 CST 1973 # 2
-------克隆對(duì)象的屬性-----
com.dpb.prototype.User@5c647e05
dpb
Tue Nov 27 14:53:51 CST 1973 # 和2的結(jié)果一樣 說明兩個(gè)對(duì)象的Date的引用是同一個(gè)
//雖然產(chǎn)生了兩個(gè)完全不同的對(duì)象揽咕,但是被復(fù)制的對(duì)象的所有變量都含有與原來的對(duì)象相同的值,而所有的對(duì)其他對(duì)象(比如Date)的引用都仍然指向原來的對(duì)象
深拷貝代碼實(shí)例:
方式一:重寫clone方法
public class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
//因?yàn)樵擃惖膶傩蕴撞耍际荢tring亲善,因此我們這里使用默認(rèn)的clone完成即可.
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class DeepProtoType implements Serializable, Cloneable {
public String name;
public DeepCloneableTarget deepCloneableTarget;
public DeepProtoType() {
super();
}
//深拷貝 - 方式1 使用clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
//完成對(duì)基本數(shù)據(jù)類型(屬性)和String的克隆
deep = super.clone();
//對(duì)引用類型的屬性,進(jìn)行單獨(dú)的處理逗柴。
DeepProtoType deepProtoType = (DeepProtoType) deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
return deep;
}
}
public class Client {
public static void main(String[] args) throws Exception{
DeepProtoType p = new DeepProtoType();
p.name="宋江";
p.deepCloneableTarget=new DeepCloneableTarget("大牛","小牛的");
//方式1 完成深拷貝
DeepProtoType p2=(DeepProtoType)p.clone();
System.out.println("p.name="+p.name+"p.deepCloneableTarget="+p.deepCloneableTarget.hashCode());
System.out.println("p2.name="+p2.name+"p.deepCloneableTarget="+p2.deepCloneableTarget.hashCode());
}
}
方式二:通過對(duì)象序列化來實(shí)現(xiàn)深拷貝(推薦使用)
DeepCloneableTarget類
public class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
//因?yàn)樵擃惖膶傩杂纪罚际荢tring,因此我們這里使用默認(rèn)的clone完成即可.
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
DeepProtoType 類
public class DeepProtoType implements Serializable, Cloneable {
public String name;
public DeepCloneableTarget deepCloneableTarget;
public DeepProtoType() {
super();
}
//深拷貝 - 方式2 通過對(duì)象序列化實(shí)現(xiàn)(推薦使用)
public Object deepClone() {
//創(chuàng)建流對(duì)象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);//當(dāng)前這個(gè)對(duì)象以對(duì)象流的方式輸出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
DeepProtoType copyObj = (DeepProtoType) ois.readObject();
return copyObj;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
Client 測試用例
public class Client {
public static void main(String[] args) throws Exception {
DeepProtoType p = new DeepProtoType();
p.name = "宋江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛的");
//方式2 完成深拷貝
DeepProtoType p3=(DeepProtoType) p.deepClone();
System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
System.out.println("p3.name=" + p3.name + "p.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode());
}
}
public class Computer {
//我們的電腦需要連接1:轉(zhuǎn)按器才可以1:網(wǎng)
public void net(NetToUsb adapter) {
//.上網(wǎng)的具體實(shí)現(xiàn)戏溺, 找“個(gè)轉(zhuǎn)接義
adapter.handleRequest();
}
public static void main(String[] args) {
Computer computer = new Computer(); //電腦
Adaptee adaptee = new Adaptee(); //網(wǎng)線
Adapter adapter = new Adapter(); //轉(zhuǎn)按器
computer.net(adapter);*/
}
結(jié)構(gòu)型模式
這些設(shè)計(jì)模式關(guān)注類和對(duì)象的組合渣蜗。
//要被適配的類:網(wǎng)線
public class Adaptee {
public void request() {
System.out.println("連接網(wǎng)線上網(wǎng)");
}
}
//真正的適配器,需 要連接USB,連接網(wǎng)線~
public class Adapter extends Adaptee implements NetToUsb {
@Override
public void handleRequest() {
//上網(wǎng)的具體實(shí)現(xiàn)旷祸,找一個(gè)轉(zhuǎn)接頭
super.request();
}
}
//按1口轉(zhuǎn)換器的抽象實(shí)現(xiàn)~
public interface NetToUsb {
//作1川:處理請(qǐng)求耕拷,網(wǎng)線=>usb
public void handleRequest();
}
public class Computer {
//我們的電腦需要連接1:轉(zhuǎn)按器才可以1:網(wǎng)
public void net(NetToUsb adapter) {
//.上網(wǎng)的具體實(shí)現(xiàn), 找“個(gè)轉(zhuǎn)接義
adapter.handleRequest();
}
public static void main(String[] args) {
/* //電腦托享,適配器骚烧,網(wǎng)線~ 使用繼承的方式
Computer computer = new Computer(); //電腦
Adaptee adaptee = new Adaptee(); //網(wǎng)線
Adapter adapter = new Adapter(); //轉(zhuǎn)按器
computer.net(adapter);*/
System.out.println("++++++++++++++++++++++++++++++");
//電腦浸赫,適配器,網(wǎng)線~ 使用組合的方式
Computer computer = new Computer(); //電腦
Adaptee adaptee = new Adaptee(); //網(wǎng)線
Adapter2 adapter = new Adapter2(adaptee); //轉(zhuǎn)按器
computer.net(adapter);
}
}
- [裝飾器模式 (Decorator Pattern):允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能赃绊,同時(shí)又不改變其結(jié)構(gòu)既峡。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個(gè)包裝碧查。何時(shí)使用:在不想增加很多子類的情況下擴(kuò)展類
第一代機(jī)器人只會(huì)跳舞运敢,第二代機(jī)器人通過傳入第一代機(jī)器人擁有了跳舞功能,然后增加唱歌功能呢忠售。
public interface Robot {
void dance();
}
public class firstRobot implements Robot {
@Override
public void dance() {
System.out.println("dance: dance");
}
}
public class twoRobot implements Robot {
protected Robot rebot;
public ShapeDecorator(Robot rebot){
this.rebot = rebot;
}
public void dance(){
rebot.dance();
}
public void singing(){
}
}
-
橋接模式 (Bridge Pattern):兩個(gè)維度獨(dú)立變化传惠,依賴方式實(shí)現(xiàn)抽象與實(shí)現(xiàn)分離:需要一個(gè)作為橋接的接口/抽象類,多個(gè)角度的實(shí)現(xiàn)類依賴注入到抽象類档痪,使它們?cè)诔橄髮咏⒁粋€(gè)關(guān)聯(lián)關(guān)系
image.png
//品牌
public interface Brand {
void info();
}
public class Lenovo implements Brand {
@Override
public void info() {
System.out.print("聯(lián)想");
}
}
public class Apple implements Brand {
@Override
public void info() {
System.out.print("蘋果");
}
}
//抽象的電腦類型類
public abstract class Computer {
//組合涉枫,品牌~
protected Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public void info() {
brand.info();//自帶品牌
}
}
class Laptop extends Computer {
public Laptop(Brand brand) {
super(brand);
}
@Override
public void info() {
super.info();
System.out.print("筆記本");
}
}
- 外觀模式 (Facade Pattern):在客戶端和復(fù)雜系統(tǒng)之間再加一層,這一次將調(diào)用順序腐螟、依賴關(guān)系等處理好愿汰。即封裝底層實(shí)現(xiàn),隱藏系統(tǒng)的復(fù)雜性乐纸,并向客戶端提供了一個(gè)客戶端可以訪問系統(tǒng)的高層接口
public class CPU {
public void startup(){
System.out.println("cpu startup!");
}
public void shutdown(){
System.out.println("cpu shutdown!");
}
}
public class Memory {
public void startup(){
System.out.println("memory startup!");
}
public void shutdown(){
System.out.println("memory shutdown!");
}
}
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!");
}
}
Computer computer = new Computer();
computer.startup();
computer.shutdown();
- 代理模式 (Proxy Pattern):為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問:增加中間層(代理層)衬廷,代理類與底層實(shí)現(xiàn)類實(shí)現(xiàn)共同接口,并創(chuàng)建底層實(shí)現(xiàn)類對(duì)象(底層實(shí)現(xiàn)類對(duì)象依賴注入代理類)汽绢,以便向外界提供功能接口
public interface Image {
void display();
}
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " + fileName);
}
}
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 圖像將從磁盤加載
image.display();
System.out.println("");
// 圖像不需要從磁盤加載
image.display();
}
}
過濾器模式 (Filter吗跋、Criteria Pattern):使用不同的標(biāo)準(zhǔn)來過濾一組對(duì)象,通過邏輯運(yùn)算以解耦的方式把它們連接起來
https://www.runoob.com/design-pattern/filter-pattern.html組合模式 (Composite Pattern):用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性的統(tǒng)一接口宁昭,何時(shí)使用: 1跌宛、您想表示對(duì)象的部分-整體層次結(jié)構(gòu)(樹形結(jié)構(gòu))。2积仗、您希望用戶忽略組合對(duì)象與單個(gè)對(duì)象的不同疆拘,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象。
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;
//構(gòu)造函數(shù)
public Employee(String name,String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List<Employee> getSubordinates(){
return subordinates;
}
public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);
Employee headSales = new Employee("Robert","Head Sales", 20000);
Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
Employee clerk1 = new Employee("Laura","Marketing", 10000);
Employee clerk2 = new Employee("Bob","Marketing", 10000);
Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
headMarketing.add(clerk1);
headMarketing.add(clerk2);
//打印該組織的所有員工
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}
- 享元模式 (Flyweight Pattern):主要用于減少創(chuàng)建對(duì)象的數(shù)量寂曹,以減少內(nèi)存占用和提高性能哎迄。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它提供了減少對(duì)象數(shù)量從而改善應(yīng)用所需的對(duì)象結(jié)構(gòu)的方式隆圆。主要解決:在有大量對(duì)象時(shí)漱挚,有可能會(huì)造成內(nèi)存溢出,我們把其中共同的部分抽象出來渺氧,如果有相同的業(yè)務(wù)請(qǐng)求旨涝,直接返回在內(nèi)存中已有的對(duì)象,避免重新創(chuàng)建侣背。
public class Circle implements Shape {
private String color;
private int x;
private int y;
private int radius;
public Circle(String color){
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setRadius(int radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Circle: Draw() [Color : " + color
+", x : " + x +", y :" + y +", radius :" + radius);
}
}
public class ShapeFactory {
private static final HashMap<String, Shape> circleMap = new HashMap<>();
public static Shape getCircle(String color) {
Circle circle = (Circle)circleMap.get(color);
if(circle == null) {
circle = new Circle(color);
circleMap.put(color, circle);
System.out.println("Creating circle of color : " + color);
}
return circle;
}
}
//隨機(jī)調(diào)用颊糜,有用過的會(huì)從hashmap中取出
public class FlyweightPatternDemo {
private static final String colors[] =
{ "Red", "Green", "Blue", "White", "Black" };
public static void main(String[] args) {
for(int i=0; i < 20; ++i) {
Circle circle =
(Circle)ShapeFactory.getCircle(getRandomColor());
circle.setX(getRandomX());
circle.setY(getRandomY());
circle.setRadius(100);
circle.draw();
}
}
private static String getRandomColor() {
return colors[(int)(Math.random()*colors.length)];
}
private static int getRandomX() {
return (int)(Math.random()*100 );
}
private static int getRandomY() {
return (int)(Math.random()*100);
}
}
行為型模式
這些設(shè)計(jì)模式特別關(guān)注對(duì)象之間的通信哩治。
- 責(zé)任鏈模式(Chain of Responsibility Pattern):攔截的類都實(shí)現(xiàn)統(tǒng)一接口,每個(gè)接收者都包含對(duì)下一個(gè)接收者的引用衬鱼。將這些對(duì)象連接成一條鏈业筏,并且沿著這條鏈傳遞請(qǐng)求,直到有對(duì)象處理它為止鸟赫。
//抽象處理者角色
abstract class Handler {
private Handler next;
public void setNext(Handler next) {
this.next = next;
}
public Handler getNext() {
return next;
}
//處理請(qǐng)求的方法
public abstract void handleRequest(String request);
}
//具體處理者角色1
class ConcreteHandler1 extends Handler {
public void handleRequest(String request) {
if (request.equals("one")) {
System.out.println("具體處理者1負(fù)責(zé)處理該請(qǐng)求蒜胖!");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("沒有人處理該請(qǐng)求!");
}
}
}
}
//具體處理者角色2
class ConcreteHandler2 extends Handler {
public void handleRequest(String request) {
if (request.equals("two")) {
System.out.println("具體處理者2負(fù)責(zé)處理該請(qǐng)求抛蚤!");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("沒有人處理該請(qǐng)求台谢!");
}
}
}
}
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
//組裝責(zé)任鏈
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setNext(handler2);
//提交請(qǐng)求
handler1.handleRequest("two");
}
}
/抽象目標(biāo)
abstract class Subject {
protected List<Observer> observers = new ArrayList<Observer>();
//增加觀察者方法
public void add(Observer observer) {
observers.add(observer);
}
//刪除觀察者方法
public void remove(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver(); //通知觀察者方法
}
//具體目標(biāo)
class ConcreteSubject extends Subject {
public void notifyObserver() {
System.out.println("具體目標(biāo)發(fā)生改變...");
System.out.println("--------------");
for (Object obs : observers) {
((Observer) obs).response();
}
}
}
//抽象觀察者
interface Observer {
void response(); //反應(yīng)
}
//具體觀察者1
class ConcreteObserver1 implements Observer {
public void response() {
System.out.println("具體觀察者1作出反應(yīng)集晚!");
}
}
//具體觀察者1
class ConcreteObserver2 implements Observer {
public void response() {
System.out.println("具體觀察者2作出反應(yīng)撒遣!");
}
}
public class ObserverPattern {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer obs1 = new ConcreteObserver1();
Observer obs2 = new ConcreteObserver2();
subject.add(obs1);
subject.add(obs2);
subject.notifyObserver();
}
}
- 模板模式(Template Pattern):將這些通用算法抽象出來绰精,在一個(gè)抽象類中公開定義了執(zhí)行它的方法的方式/模板。主要解決:一些方法通用叮趴,卻在每一個(gè)子類都重新寫了這一方法扑眉。
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戲
initialize();
//開始游戲
startPlay();
//結(jié)束游戲
endPlay();
}
}
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
//不用命令模式条篷,添加一個(gè)界面就要修改電視類和觀看類
//電視機(jī)對(duì)象:提供了播放不同頻道的方法
public class Television {
public void playCctv1() {
System.out.println("--CCTV1--");
}
public void playCctv2() {
System.out.println("--CCTV2--");
}
}
public class Watcher {
//持有一個(gè)
public Television tv;
public Watcher(Television tv) {
this.tv = tv;
}
public void playCctv1() {
tv.playCctv1();
}
public void playCctv2() {
tv.playCctv2();
}
}
Watcher watcher = new Watcher(new Television());
watcher.playCctv1();
watcher.playCctv2();
//使用命令模式
public abstract class Command {
//命令接收者:電視機(jī)
protected Television television;
public Command(Television television) {
this.television = television;
}
//命令執(zhí)行
abstract void execute();
}
//播放cctv1的命令
public class CCTV1Command extends Command {
@Override
void execute() {
television.playCctv1();
}
}
//播放cctv2的命令
public class CCTV6Command extends Command {
@Override
void execute() {
television.playCctv2();
}
}
————————————————
historyCommand.add(command);
command.execute();
}
//遙控器返回命令
public class TeleController {
//播放記錄
List<Command> historyCommand = new ArrayList<Command>();
//切換衛(wèi)視
public void switchCommand(Command command) {
historyCommand.add(command);
command.execute();
}
public void back() {
if (historyCommand.isEmpty()) {
return;
}
int size = historyCommand.size();
int preIndex = size-2<=0?0:size-2;
//獲取上一個(gè)播放某衛(wèi)視的命令
Command preCommand = historyCommand.remove(preIndex);
preCommand.execute();
}
}
//創(chuàng)建一個(gè)電視機(jī)
Television tv = new Television();
//創(chuàng)建一個(gè)遙控器
TeleController teleController = new TeleController();
teleController.switchCommand(new CCTV1Command(tv));
teleController.switchCommand(new CCTV2Command(tv));
//模擬遙控器返回鍵
teleController.back();
teleController.back();
解釋器模式(Interpreter Pattern):給定一個(gè)語言,定義它的文法表示蛤织,并定義一個(gè)解釋器赴叹,這個(gè)解釋器使用該標(biāo)識(shí)來解釋語言中的句子
何時(shí)使用:如果一種特定類型的問題發(fā)生的頻率足夠高,那么可能就值得將該問題的各個(gè)實(shí)例表述為一個(gè)簡單語言中的句子指蚜。這樣就可以構(gòu)建一個(gè)解釋器乞巧,該解釋器通過解釋這些句子來解決該問題。迭代器模式(Iterator Pattern):集合中含有迭代器:分離了集合對(duì)象的遍歷行為姚炕,抽象出一個(gè)迭代器類來負(fù)責(zé),無須暴露該對(duì)象的內(nèi)部表示
中介者模式(Mediator Pattern):對(duì)象與對(duì)象之間存在大量的關(guān)聯(lián)關(guān)系丢烘,將對(duì)象之間的通信關(guān)聯(lián)關(guān)系封裝到一個(gè)中介類中單獨(dú)處理柱宦,從而使其耦合松散,可以獨(dú)立地改變它們之間的交互
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
public interface Strategy {
public int doOperation(int num1, int num2);
}
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
狀態(tài)模式(State Pattern):狀態(tài)對(duì)象依賴注入到context對(duì)象掸刊,context對(duì)象根據(jù)它的狀態(tài)改變而改變它的相關(guān)行為(可通過調(diào)用內(nèi)部的狀態(tài)對(duì)象實(shí)現(xiàn)相應(yīng)的具體行為)
備忘錄模式(Memento Pattern):通過一個(gè)備忘錄類專門存儲(chǔ)對(duì)象狀態(tài)∮遥客戶通過備忘錄管理類管理備忘錄類忧侧。
空對(duì)象模式(Null Object Pattern):創(chuàng)建一個(gè)未對(duì)該類做任何實(shí)現(xiàn)的空對(duì)象類石窑,該空對(duì)象類將無縫地使用在需要檢查空值的地方。不要為了屏蔽null而使用空對(duì)象蚓炬,應(yīng)保持用null松逊,遠(yuǎn)比用非null的值來替代“無值”要好。(慎用)