注解
注解:也叫標(biāo)注,用于包、類、變量、方法、參數(shù)上??梢酝ㄟ^反射獲取標(biāo)注??梢栽诰幾g期間使用,也可以被編譯到字節(jié)碼文件中,運(yùn)行時(shí)生效。
內(nèi)置注解
內(nèi)置注解:Java語言已經(jīng)定義好的注解。
@Overread:用于方法重寫。
@Deprecated:標(biāo)記過時(shí)方法。
@SuppressWarnings:指示編譯器去忽略注解中聲明的警告。
@FunctionalInterface:用于指標(biāo)被修飾的接口是函數(shù)式接口。
元注解
元注解:修飾注解的注解。
@Target:用于描述注解作用于那些元素上。
CONSTRUCTOR//用于描述構(gòu)造器
FIELD//用于描述域
LOCAL_VARIABLE//用于描述局部變量
METHOD//用于描述方法
PACKAGE//用于描述包
PARAMETER//用于描述參數(shù)
TYPE//用于描述類、接口(包括注解類型) 或enum聲明
@Retention:表示注解什么時(shí)候生效。
SOURCE//在源文件中有效(即源文件保留)
CLASS//在class文件中有效(即class保留)
RUNTIME//在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)
對象克隆
克隆:在一個(gè)現(xiàn)有的對象基礎(chǔ)上克隆一個(gè)新的對象。
為什么要克?。?/h3>
通過new出來的對象,所有屬性都是空值或者默認(rèn)值,希望將原來對象的屬性也一并賦值給一個(gè)新的對象。
//一下情況并不是克隆,只是將對象地址賦值給了另一個(gè)對象.
Student stu1 = new Student();
Student stu2 = stu1;
如何克隆
- 類實(shí)現(xiàn)Cloneable接口,重寫Object類中的clone方法。
- 通過序列化來實(shí)現(xiàn)。
java語言中數(shù)據(jù)類型分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,基本數(shù)據(jù)類型的值可以直接進(jìn)行復(fù)制,但是引用數(shù)據(jù)類型只能復(fù)制引用地址。所以淺克隆和深克隆的區(qū)別就在于是否支持引用類型的成員變量的復(fù)制。
淺克隆
不支持對象中的引用類型復(fù)制值,僅僅復(fù)制地址。
簡單來說就是,當(dāng)對象被克隆時(shí)只復(fù)制它本身,和其他基本數(shù)據(jù)類型的成員變量,而引用類型的對象并沒有復(fù)制。
深克隆
支持對象中的引用類型成員變量復(fù)制值,引用類型成員變量也會克隆一個(gè)新的對象。
簡單來說,就是除了對象本身被復(fù)制外,對象包含的所有成員變量也將復(fù)制。
Java設(shè)計(jì)模式
設(shè)計(jì)模式本來是在建筑上使用的,后來運(yùn)用于程序設(shè)計(jì)。
什么是設(shè)計(jì)模式?
設(shè)計(jì)模式是指一套被反復(fù)使用,代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。針對一些問題的解決方式,經(jīng)過很長時(shí)間的修改打磨最終成為一種固定的模式。
為什么要學(xué)習(xí)設(shè)計(jì)模式?
在面向?qū)ο蟮幕A(chǔ)上(繼承、封裝、多態(tài)),更好的理解和運(yùn)用。
使用設(shè)計(jì)模式的優(yōu)點(diǎn):
可以提高程序員的思維、編程、設(shè)計(jì)能力;
使程序更加標(biāo)準(zhǔn)化,提高軟件開發(fā)效率;
使得代碼的可重用性高,可讀性強(qiáng),靈活性好,可維護(hù)性強(qiáng);
更好的理解源代碼。
建模語言
統(tǒng)一建模語言(Unified Modeling Language,UML)是一種用于軟件系統(tǒng)分析和設(shè)計(jì)的語言工具,用于幫助開發(fā)人員進(jìn)行思考和記錄思路的結(jié)果。
UML圖:通過不同的圖形和符號,描述軟件模型以及各個(gè)元素之間的聯(lián)系。
類圖:是顯示了模型的靜態(tài)結(jié)構(gòu),特別是模型中存在的類、類的內(nèi)部結(jié)構(gòu)以及他們與其它類之間的關(guān)系等。類圖是面向?qū)ο蠼5闹饕M成部分。
類圖是一種靜態(tài)的結(jié)構(gòu)圖,描述了系統(tǒng)的類的集合,類的屬性和類之間的關(guān)系,可以簡化人們對系統(tǒng)的理解;類圖是系統(tǒng)分析與設(shè)計(jì)的產(chǎn)物。
類
類是指具有相同屬性、方法和關(guān)系的對象的抽象,它封裝了數(shù)據(jù)的行為,是面向?qū)ο蟪绦蛟O(shè)計(jì)的基礎(chǔ),具有封裝、繼承和多態(tài)三種特性。
在UML中,類的UML:
—no:long 表示不可見參數(shù)no的數(shù)據(jù)類型為long;
+display():void表示方法display為public,且返回值為void;
protected(#)
接口
接口是一種特殊的類,它具有類的結(jié)構(gòu)但是不能實(shí)例化,只可以被子類實(shí)現(xiàn)。它包含抽象操作,但是不包含屬性。它描述了類或組件對外可見的動作。
在UML中,接口使用一個(gè)帶有名稱的圓圈表示。
類之間的關(guān)系
在系統(tǒng)中,類并不是孤立存在的,類與類之間存在一定關(guān)系的。根據(jù)類之間的耦合度從弱到強(qiáng)依次為:依賴關(guān)系、關(guān)聯(lián)關(guān)系、聚合關(guān)系、組合關(guān)系、泛化關(guān)系和實(shí)現(xiàn)關(guān)系。
依賴關(guān)系
依賴關(guān)系是一種臨時(shí)關(guān)系。代碼中,某個(gè)類的方法通過局部變量、方法的參數(shù)或者對靜態(tài)方法的調(diào)用來訪問另一個(gè)類(被依賴類)中的某些方法來完成某些功能。
在UML類圖中,依賴關(guān)系使用帶箭頭的虛線表示,從使用類指向被依賴類。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-lLETOFmh-1692757184340)(
)]
關(guān)聯(lián)關(guān)系
關(guān)聯(lián)關(guān)系是對象之間的一種引用關(guān)系,用于表示一類對象與另一類對象之間的聯(lián)系,如老師與學(xué)生等。關(guān)聯(lián)關(guān)系是類與類之間最常用的一種關(guān)系,分為關(guān)聯(lián)關(guān)系,聚合關(guān)系和組合關(guān)系。
關(guān)聯(lián)關(guān)系一般分為單向關(guān)聯(lián)、雙向關(guān)聯(lián)、自關(guān)聯(lián)。
單向關(guān)聯(lián):
在 UML 類圖中單向關(guān)聯(lián)用一個(gè)帶箭頭的實(shí)線表示。上圖表示每個(gè)顧客都有一個(gè)地址,這通過讓 Customer 類持有一個(gè)類型為 Address 的成員變量類實(shí)現(xiàn)。
雙向關(guān)聯(lián):
從上圖中我們很容易看出,所謂的雙向關(guān)聯(lián)就是雙方各自持有對方類型的成員變量。
在 UML 類圖中,雙向關(guān)聯(lián)用一個(gè)不帶箭頭的直線表示。
自關(guān)聯(lián):
自關(guān)聯(lián)在 UML 類圖中用一個(gè)帶有箭頭且指向自身的線表示。上圖的意思就是Node 類包含類型為 Node 的成員變量,也就是“自己包含自己”。
聚合關(guān)系
聚合關(guān)系是關(guān)聯(lián)關(guān)系的一種,是整體與部分之間的關(guān)系。
聚合關(guān)系也是通過成員對象來實(shí)現(xiàn)的,其中成員對象是整體對象的一部分,但是成員對象可以脫離整體對象而獨(dú)立存在。例如,學(xué)校與老師的關(guān)系,學(xué)校包含老師,但如果學(xué)校停辦了,老師依然存在。
在 UML 類圖中,聚合關(guān)系可以用帶空心菱形的實(shí)線來表示,菱形指向整體。
組合關(guān)系
組合表示類之間的整體與部分的關(guān)系,但它是一種更強(qiáng)烈的聚合關(guān)系。
在組合關(guān)系中,整體對象可以控制部分對象的生命周期,一旦整體對象不存在,部分對象也將不存在,部分對象不能脫離整體對象而存在。例如,頭和嘴的關(guān)系,沒有了頭,嘴也就不存在了。
在 UML 類圖中,組合關(guān)系用帶實(shí)心菱形的實(shí)線來表示,菱形指向整體。
繼承關(guān)系
繼承關(guān)系是對象之間耦合度最大的一種關(guān)系,表示一般與特殊的關(guān)系,是父類與子類之間的關(guān)系,是一種繼承關(guān)系。
在 UML 類圖中,繼承關(guān)系用帶空心三角箭頭的實(shí)線來表示,箭頭從子類指向父類。在代碼實(shí)現(xiàn)時(shí),使用面向?qū)ο蟮睦^承機(jī)制來實(shí)現(xiàn)繼承關(guān)系。例如上圖, Student 類和 Teacher 類都是 Person 類的子類。
實(shí)現(xiàn)關(guān)系
實(shí)現(xiàn)關(guān)系是接口與實(shí)現(xiàn)類之間的關(guān)系。在這種關(guān)系中,類實(shí)現(xiàn)了接口,類中的操作實(shí)現(xiàn)了接口中所聲明的所有的抽象操作。
在 UML 類圖中,實(shí)現(xiàn)關(guān)系使用帶空心三角箭頭的虛線來表示,箭頭從實(shí)現(xiàn)類指向接口。例如上圖,汽車和船實(shí)現(xiàn)了交通工具。
面向?qū)ο笤O(shè)計(jì)原則
如何同時(shí)提高系統(tǒng)的可維護(hù)性和可服用性。就需要遵從面向?qū)ο笳Z言設(shè)計(jì)原則,可以在進(jìn)行設(shè)計(jì)方案時(shí)減少設(shè)計(jì)錯(cuò)誤,提高軟件的實(shí)際水平。
單一職責(zé)
單一職責(zé)可以理解為一個(gè)類只負(fù)責(zé)一個(gè)功能領(lǐng)域中的相應(yīng)職責(zé)。
優(yōu)點(diǎn):低耦合、高內(nèi)聚。
開閉原則
開閉原則:擴(kuò)展開放,修改關(guān)閉。
系統(tǒng)的需求是一直在變化的,因此在設(shè)計(jì)時(shí)需要考慮怎樣設(shè)計(jì)才能在需求改變時(shí),系統(tǒng)依舊可以穩(wěn)定。
需要系統(tǒng)進(jìn)行抽象化設(shè)計(jì),抽象化是開閉原則的關(guān)鍵。在進(jìn)行軟件設(shè)計(jì)時(shí)提前將一些可能會改變的類設(shè)計(jì)為抽象類來隔離變化。在發(fā)生變化時(shí),無需對抽象類進(jìn)行改動,只需要添加具體類來實(shí)現(xiàn)業(yè)務(wù)功能即可。在不修改自己原有的代碼的基礎(chǔ)上擴(kuò)展功能。
/*
開閉原則案例
*/
public class CarDemo {
public static void main(String[] args) {
new CarFactory().createCar(1);
new CarFactory().createCar(2);
new CarFactory().createCar(3);
new CarFactory().createCar(4);
new CarFactory().createCar(5);
}
}
/*
汽車工程類,專門負(fù)責(zé)造汽車
*/
class CarFactory{
/*
違反了開閉原則,后期如果添加新的汽車類,則需要修改代碼
*/
public void createCar(int type){
if(type==1){
System.out.println("造寶馬汽車"+new Car("寶馬汽車"));
}else if(type==2){
System.out.println("造奧迪汽車"+new Car("奧迪汽車"));
}else{
System.out.println("造大眾汽車"+new Car("大眾汽車"));
}
}
}
class Car{
String name;
public Car(String name) {
this.name = name;
}
}
class CarDemo{
public static void main(String[] args) {
new CarFactory().carfactory(new BMW());
new CarFactory().carfactory(new Aodi());
new CarFactory().carfactory(new DaZhong());
}
}
class CarFactory{
void carfactory(Car car){
car.createCar();
}
}
//擴(kuò)展業(yè)務(wù)時(shí)只需要繼承Car類無需修改原代碼
abstract class Car{
public abstract void createCar();
}
class BMW extends Car{
@Override
public void createCar() {
System.out.println("造寶馬汽車");
}
}
class Aodi extends Car{
@Override
public void createCar() {
System.out.println("造奧迪汽車");
}
}
class DaZhong extends Car{
@Override
public void createCar() {
System.out.println("造大眾汽車");
}
}
class BC extends Car{
@Override
public void createCar() {
System.out.println("造奔馳汽車");
}
}
優(yōu)點(diǎn):適應(yīng)性強(qiáng)、靈活、穩(wěn)定、可擴(kuò)展性強(qiáng)、可復(fù)用。
里氏替換原則
回顧繼承:
優(yōu)勢:提高了代碼的復(fù)用性,提高了代碼的擴(kuò)展性。
弊端:繼承是侵入式(只要繼承,就必須擁有父類的屬性和方法);繼承機(jī)制很大的增加了耦合性(父類被子類繼承,父類功能修改會影響子類)。
里氏替換原則:繼承必須確保父類所擁有的性質(zhì)子類中必然成立。
里氏替換原則的定義:通俗的講就是,子類繼承父類時(shí)除添加新的方法完成新增功能外盡量不要重寫父類的方法。
public class CalculatorDemo{
public static void main(String[] args) {
System.out.println(new SuperCalculator().sum(5,5,5));
}
}
//計(jì)算器 基類
class Calculator {
//加法
public int add(int a,int b){
return a+b;
}
//減法
public int sub(int a,int b){
return a-b;
}
}
/*
超級計(jì)算器子類
*/
class SuperCalculator extends Calculator{
//重寫了父類加法
@Override
public int add(int a, int b) {
return a+b+5;
}
//求和方法 子類新增的功能
public int sum(int a,int b,int c){
//調(diào)用add(),但是子類重寫了父類方法,此處調(diào)用的子類方法發(fā)生了變化,這里相當(dāng)于調(diào)用了重寫的add方法,
int result = add(a,b);//重寫add后結(jié)果為20,不重寫結(jié)果為15
return result+c;
}
}
里氏替換原則的作用:功能正確性得到保障,實(shí)現(xiàn)開閉原則的重要方式之一,降低了需求變更時(shí)引入的風(fēng)險(xiǎn)。
依賴倒置
上層模塊不應(yīng)該依賴底層模塊,它們都應(yīng)該依賴于抽象
簡單講就是:要求對抽象進(jìn)行編程,不要對實(shí)現(xiàn)進(jìn)行編程,這樣就降低了客戶與實(shí)現(xiàn)模塊間的耦合。就是針對抽象層編程,面向接口編程。
接口隔離
使用多個(gè)接口,而不使用單一的總接口,不強(qiáng)迫新功能實(shí)現(xiàn)不需要的方法。
迪米特原則
一個(gè)對象應(yīng)該對其他對象有最少的了解
就是只對直接朋友進(jìn)行交流
public class Demeter {
public static void main(String[] args) {
new SchoolManger().printAllEmployee(new CollegeManger());
}
}
/*
學(xué)校員工類
*/
class SchoolEmployee{
private String id;
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
}
/*
學(xué)院員工類
*/
class CollegeEmployee{
private String id;
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
}
//學(xué)院員工管理管理類
class CollegeManger{
//生成學(xué)院所有的員工
public List<CollegeEmployee> getCollegeEmployee(){
ArrayList<CollegeEmployee> collegeEmployeeArrayList = new ArrayList<CollegeEmployee>();
for (int i = 0; i <10 ; i++) {
CollegeEmployee collegeEmployee = new CollegeEmployee();
collegeEmployee.setId("學(xué)院員工的id="+i); //添加學(xué)院員工
collegeEmployeeArrayList.add(collegeEmployee);
}
return collegeEmployeeArrayList;
}
}
//學(xué)校員工管理類
class SchoolManger {
//生成學(xué)校的員工
public List<SchoolEmployee> getSchoolEmployee() {
ArrayList<SchoolEmployee> employeeArrayList = new ArrayList<SchoolEmployee>();
for (int i = 0; i < 5; i++) {
SchoolEmployee employee = new SchoolEmployee();
employee.setId("學(xué)校的員工id=" + i);
employeeArrayList.add(employee);
}
return employeeArrayList;
}
//輸出學(xué)校員工和學(xué)院員工信息
public void printAllEmployee(CollegeManger collegeManger) {
//獲取到學(xué)校員工
List<SchoolEmployee> employeeArrayList = this.getSchoolEmployee();
System.out.println("--------學(xué)校員工--------");
for (SchoolEmployee employee1 : employeeArrayList) {
System.out.println(employee1.getId());
}
System.out.println("--------學(xué)院員工--------");
List<CollegeEmployee> collegeEmployees = collegeManger.getCollegeEmployee();
//此處學(xué)校管理類中出現(xiàn)CollegeEmployee,此類與SchoolManger并非直接朋友,不合理
for (CollegeEmployee collegeEmployee : collegeEmployees) {
System.out.println(collegeEmployee.getId());
}
}
}
public class Demeter {
public static void main(String[] args) {
new SchoolManger().printAllEmployee(new CollegeManger());
}
}
/*
學(xué)校員工類
*/
class SchoolEmployee{
private String id;
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
}
/*
學(xué)員員工類
*/
class CollegeEmployee{
private String id;
public void setId(String id){
this.id = id;
}
public String getId(){
return id;
}
}
//學(xué)院員工管理管理類
class CollegeManger{
//生成學(xué)員所有的員工
public List<CollegeEmployee> getCollegeEmployee(){
ArrayList<CollegeEmployee> collegeEmployeeArrayList = new ArrayList<CollegeEmployee>();
for (int i = 0; i <10 ; i++) {
CollegeEmployee collegeEmployee = new CollegeEmployee();
collegeEmployee.setId("學(xué)院員工的id="+i); //添加學(xué)院員工
collegeEmployeeArrayList.add(collegeEmployee);
}
return collegeEmployeeArrayList;
}
public void printCollegeEmployee(){
List<CollegeEmployee> collegeEmployee = getCollegeEmployee();
for (CollegeEmployee employee : collegeEmployee) {
System.out.println("學(xué)員員工id="+employee.getId());
}
}
}
//學(xué)校員工管理類
class SchoolManger {
//生成學(xué)校的員工
public List<SchoolEmployee> getSchoolEmployee() {
ArrayList<SchoolEmployee> employeeArrayList = new ArrayList<SchoolEmployee>();
for (int i = 0; i < 5; i++) {
SchoolEmployee employee = new SchoolEmployee();
employee.setId("學(xué)校的員工id=" + i);
employeeArrayList.add(employee);
}
return employeeArrayList;
}
//輸出學(xué)校員工和學(xué)院員工信息
public void printAllEmployee(CollegeManger collegeManger) {
//獲取到學(xué)校員工
List<SchoolEmployee> employeeArrayList = this.getSchoolEmployee();
System.out.println("--------學(xué)校員工--------");
for (SchoolEmployee employee1 : employeeArrayList) {
System.out.println(employee1.getId());
}
//CollegeManger與SchoolManger是直接朋友,相互之間訪問
System.out.println("--------學(xué)員員工-----------");
collegeManger.printCollegeEmployee();
}
}
組合/聚合服用原則
優(yōu)先使用組合,使系統(tǒng)更靈話,其次才考慮繼承,達(dá)到復(fù)用的目的。
案例:現(xiàn)在假設(shè)有一個(gè) A 類,里面有兩個(gè)方法,有一個(gè)類 B,想要復(fù)用這兩個(gè)方法,請問有幾種方案?
方案一:讓B繼承A;
方案二:B中引用A;
方案三:方法傳參;
原則總結(jié):
開閉原則:要求對擴(kuò)展開放,對修改關(guān)閉
里氏替換原則:不要破壞繼承體系
依賴倒置原則:要求面向接口編程
單一職責(zé)原則:實(shí)現(xiàn)類職責(zé)要單一
接口隔離原則:在設(shè)計(jì)接口的時(shí)候要精簡單一
迪米特法則:只與直接的朋友的通信
合成復(fù)用原則:盡量使用聚合和組合的方式,而不是使用繼承
設(shè)計(jì)原則的核心思想
找出應(yīng)用中可能需要變化之處,獨(dú)立出來,不要和不需要變化的代碼混在一起
針對接口編程,而壞是針對實(shí)現(xiàn)編程
為了交互對象的松耦合設(shè)計(jì)而努力
遵循設(shè)計(jì)原則:就是為了讓程序高內(nèi)聚,低耦合
23種設(shè)計(jì)模式
https://www.runoob.com/design-pattern/design-pattern-tutorial.html
- 單例(Singleton)模式:某個(gè)類只能生成一個(gè)實(shí)例,該類提供了一個(gè)全局訪問點(diǎn)供外部獲取該實(shí)例,其拓展是有限多例模式。
- 原型(Prototype)模式:將一個(gè)對象作為原型,通過對其進(jìn)行復(fù)制而克隆出多個(gè)和原型類似的新實(shí)例。
- 工廠方法(Factory Method)模式:定義一個(gè)用于創(chuàng)建產(chǎn)品的接口,由子類決定生產(chǎn)什么產(chǎn)品。
- 抽象工廠(AbstractFactory)模式:提供一個(gè)創(chuàng)建產(chǎn)品族的接口,其每個(gè)子類可以生產(chǎn)一系列相關(guān)的產(chǎn)品。
- 建造者(Builder)模式:將一個(gè)復(fù)雜對象分解成多個(gè)相對簡單的部分,然后根據(jù)不同需要分別創(chuàng)建它們,最后構(gòu)建成該復(fù)雜對象。
- 代理(Proxy)模式:為某對象提供一種代理以控制對該對象的訪問。即客戶端通過代理間接地訪問該對象,從而限制、增強(qiáng)或修改該對象的一些特性。
- 適配器(Adapter)模式:將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口,使得原本由于接口不兼容而不能一起工作的那些類能一起工作。
- 橋接(Bridge)模式:將抽象與實(shí)現(xiàn)分離,使它們可以獨(dú)立變化。它是用組合關(guān)系代替繼承關(guān)系來實(shí)現(xiàn),從而降低了抽象和實(shí)現(xiàn)這兩個(gè)可變維度的耦合度。
- 裝飾(Decorator)模式:動態(tài)的給對象增加一些職責(zé),即增加其額外的功能。
- 外觀(Facade)模式:為多個(gè)復(fù)雜的子系統(tǒng)提供一個(gè)一致的接口,使這些子系統(tǒng)更加容易被訪問。
- 享元(Flyweight)模式:運(yùn)用共享技術(shù)來有效地支持大量細(xì)粒度對象的復(fù) 用。
- 組合(Composite)模式:將對象組合成樹狀層次結(jié)構(gòu),使用戶對單個(gè)對象和組合對象具有一致的訪問性。
- 模板方法(TemplateMethod)模式:定義一個(gè)操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結(jié)構(gòu)的情況下重定義該算法的某些特定步驟。
- 策略(Strategy)模式:定義了一系列算法,并將每個(gè)算法封裝起來,使它們可以相互替換,且算法的改變不會影響使用算法的客戶。
- 命令(Command)模式:將一個(gè)請求封裝為一個(gè)對象,使發(fā)出請求的責(zé)任和執(zhí)行請求的責(zé)任分割開。
- 職責(zé)鏈(Chain of Responsibility)模式:把請求從鏈中的一個(gè)對象傳到下一個(gè)對象,直到請求被響應(yīng)為止。通過這種方式去除對象之間的耦合。
- 狀態(tài)(State)模式:允許一個(gè)對象在其內(nèi)部狀態(tài)發(fā)生改變時(shí)改變其行為能 力。
- 觀察者(Observer)模式:多個(gè)對象間存在一對多關(guān)系,當(dāng)一個(gè)對象發(fā)生改變時(shí),把這種改變通知給其他多個(gè)對象,從而影響其他對象的行為。
- 中介者(Mediator)模式:定義一個(gè)中介對象來簡化原有對象之間的交互關(guān)系,降低系統(tǒng)中對象間的耦合度,使原有對象之間不必相互了解。
- 迭代器(Iterator)模式:提供一種方法來順序訪問聚合對象中的一系列數(shù) 據(jù),而不暴露聚合對象的內(nèi)部表示。
- 訪問者(Visitor)模式:在不改變集合元素的前提下,為一個(gè)集合中的每個(gè)元素提供多種訪問方式,即每個(gè)元素有多個(gè)訪問者對象訪問。
- 備忘錄(Memento)模式:在不破壞封裝性的前提下,獲取并保存一個(gè)對象的內(nèi)部狀態(tài),以便以后恢復(fù)它。
- 解釋器(Interpreter)模式:提供如何定義語言的文法,以及對語言句子的解釋方法,即解釋器。
常用的設(shè)計(jì)模式
單例模式
有些系統(tǒng)或者項(xiàng)目中,為了節(jié)省資源、保證數(shù)據(jù)內(nèi)容的一致性,對某些類要求只能創(chuàng)建一個(gè)對象實(shí)例。如Windows中的只能打開一個(gè)任務(wù)管理器,這樣可以避免因?yàn)榇蜷_多個(gè)任務(wù)管理器窗口而造成內(nèi)存資源浪費(fèi),或者出現(xiàn)各個(gè)窗口顯示的內(nèi)容不一致等錯(cuò)誤。
特點(diǎn):
只能有一個(gè)實(shí)例對象
單例對象必須由單例類自行創(chuàng)建(關(guān)聯(lián)關(guān)系中的自關(guān)聯(lián))
單例類需要對外提供一個(gè)訪問單例的全局訪問點(diǎn)
單例模式實(shí)現(xiàn)形式有兩種:餓漢式、懶漢式。
餓漢式單例
在類被加載時(shí)創(chuàng)建對象,不存在線程安全問題。
public class Window {
//創(chuàng)建靜態(tài)對象,隨著類的加載一起加載
private static Window window = new Window();
private Window(){}//構(gòu)造方法私有化,防止外部直接構(gòu)造
//提供給外部獲取實(shí)例對象的方法
public static Window getWindow() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return window;
}
}
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
System.out.println(Window.getWindow());
}).start();
}
}
}
/*
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
com.single.demo1.Window@6bfcab86
*/
//由結(jié)果可以看出創(chuàng)建的十個(gè)對象是同一個(gè)對象
懶漢式單例
在類加載的時(shí)候不創(chuàng)建對象,在使用的時(shí)候創(chuàng)建。這時(shí)生成的對象需要我們自己進(jìn)行控制,存在線程安全問題。
public class Window {
private static Window window=null;
private Window(){}
/*
懶漢式單例會出現(xiàn)線程安全問題:
在多線程訪問時(shí),可能會有多個(gè)線程同時(shí)進(jìn)行到if,就會創(chuàng)建出多個(gè)對象
*/
public static Window getWindow(){
if(window==null){
window = new Window();
}
return window;
}
}
//解決方法1.給方法加鎖, 可以解決,但是效率低,一次只能有一個(gè)線程進(jìn)入獲取
public static synchronized Window getWindow() {
if (window == null) {
window = new Window();
}
return window;
}
//解決方法2.給代碼塊加鎖,雙重檢索+synchronized
public static Window getWindow(){
if(window==null){
synchronized(Window.class){
if(window == null){
window = new Window3();
}
}
}
return window;
}
經(jīng)過上面兩次改進(jìn)任然存在問題,就是指令重排問題,new一個(gè)對象的時(shí)候一般步驟為:申請空間——調(diào)用構(gòu)造方法——將對象地址賦值給引用變量。
問題:在一個(gè)線程先將半成品對象地址賦值給引用變量時(shí)暫停了,另一線程來了引用變量不為空,指向半成品對象。
解決方法:在解決辦法2的基礎(chǔ)上加volatile文章來源:http://www.zghlxwxcb.cn/news/detail-673672.html
private static volatile Window window=null;
Runtime類
Jdk 中的源碼 Runtime 類就是一個(gè)單例類,利用 Runtime 類可以啟動新的進(jìn)程或進(jìn)行相關(guān)運(yùn)行時(shí)環(huán)境的操作。比如,取得內(nèi)存空間以及釋放垃圾空間。文章來源地址http://www.zghlxwxcb.cn/news/detail-673672.html
到了這里,關(guān)于一網(wǎng)打盡java注解-克隆-面向?qū)ο笤O(shè)計(jì)原則-設(shè)計(jì)模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!