面向對象的一些重要設計模式:
1)簡單工廠模式:
簡單來講就是創建一個工廠類並提供一些靜態方法間接的去創建具體類對象
下面我們用一個例子來簡單說明一下:
例如:
先創建一個抽象Animal類:
package com.westos_01;
/**
*創建一個抽象動物類,並提供抽象方法
*/
public abstract class Animal {
public abstract void eat() ;
}
再創建兩個子類:
package com.westos_01;
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗愛吃骨頭...");
}
}
package com.westos_01;
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("貓愛吃魚...");
}
}
再去創建一個工廠類:
package com.westos_01;
/**
*創建一個動物工廠類
*並提供一些靜態方法
*/
public class AnimaiFactory {
//創建該類的私有無參構造,使它不能在創建類對象
private AnimaiFactory() {
}
/*
//創建一個返回狗類的靜態方法
public static Dog createDog() {
return new Dog();
}
//創建一個返回貓類的靜態方法
public static Cat createCat() {
return new Cat();
}
*/
//改進方法
public static Animal createAnimal(String type) {
if("cat".equals(type)) {
return new Cat();
}else if("dog".equals(type)) {
return new Dog();
}
return null;
}
}
最後創建一個測試類:
package com.westos_01;
/**
* @author 傑哥
*簡單工廠模式--->靜態工廠方法模式
* 創建一個工廠類:
* 工廠類提供一些靜態方法,間接的去創建具體的對象
*/
public class AnimalDome {
public static void main(String[] args) {
/*
//**
* 創建工廠類的優點:
* 不需要刻意的去創建具體類的對象,把它交給工廠類去創建就可以了
* 創建工廠類的弊端:
* 如果有新的對象增加,或者某些對象的創建方式不同,就需要不斷的修改工廠類,不利於後期的維護
*
//調用工廠類的靜態方法
Dog dog = AnimaiFactory.createDog();
Cat cat = AnimaiFactory.createCat();
dog.eat();
cat.eat();
*/
/**
* 所以我們需要對上述的問題進行改進優化
*/
Animal dog = AnimaiFactory.createAnimal("dog");
dog.eat();
//這裏並沒有返回Animal類,只是將它給了dog
dog=AnimaiFactory.createAnimal("cat");
dog.eat();
Animal cat = AnimaiFactory.createAnimal("cat");
cat.eat();
//當我們在createAnimal方法中輸入的類型並沒有創建,我們應該進行非空判斷
cat=AnimaiFactory.createAnimal("pig");
if(cat!=null) {
cat.eat();
}else {
System.out.println("您輸入的類型不存在,請重新輸入...");
}
}
}
運行結果:
狗愛吃骨頭...
貓愛吃魚...
貓愛吃魚...
您輸入的類型不存在,請重新輸入...
上面學習了一個簡單工廠模式,下面我們看一個工廠方法模式:
工廠方法模式
提供一個抽象類(抽象工廠)還需要提供一個接口(工廠接口),每一個具體的類都有對應的工廠類(實現工廠接口)
具體對象的創建工作由繼承抽象工廠的具體類實現
優點:
客戶端不需要在負責對象的創建(不需顯示創建具體對象),從而明確了各個類的職責,如果有新的對象增加,只需要增加一個具體的類和具體的工廠類即可,不影響已有的代碼,後期維護容易,增強了系統的擴展性
弊端:
書寫代碼量大了!
下面我們用代碼實現:
創建一個抽象動物類:
package com.westos_02;
public abstract class Animal {
//創建抽象方法
public abstract void play();
}
創建兩個子類繼承它
package com.westos_02;
public class Dog extends Animal{
@Override
public void play() {
System.out.println("狗喜歡玩泥巴...");
}
}
package com.westos_02;
public class Cat extends Animal{
@Override
public void play() {
System.out.println("貓喜歡玩泥鰍...");
}
}
創建一個工廠接口:
package com.westos_02;
/**
*創建一個工廠接口
*然後讓它的子實現類去實現它,
*這些子實現類就是Animal類的子類的工廠類
*/
public interface Factory {
public abstract Animal createAnimal();
}
創建兩個子工廠實現類:
package com.westos_02;
public class DogFactory implements Factory{
@Override
public Animal createAnimal() {
return new Dog();
}
}
package com.westos_02;
public class CatFactory implements Factory{
@Override
public Animal createAnimal() {
return new Cat();
}
}
最後創建一個測試類:
package com.westos_02;
/**
*工廠方法模式
* 提供一個抽象類(抽象工廠)還需要提供一個接口(工廠接口),每一個具體的類都有對應的工廠類(實現工廠接口)
* 具體對象的創建工作由繼承抽象工廠的具體類實現
*
*優點:
* 客戶端不需要在負責對象的創建(不需顯示創建具體對象),從而明確了各個類的職責,
* 如果有新的對象增加,只需要增加一個具體的類和具體的工廠類即可,不影響已有的代碼,後期維護容易,增強了系統的擴展性
弊端:
書寫代碼量大了!
*
*
*/
public class AnimalDome {
public static void main(String[] args) {
//使用多態的方式去創建Factory接口的對象
Factory f=new DogFactory();
Animal dog = f.createAnimal();
dog.play();
System.out.println("---------------");
dog=new CatFactory().createAnimal();
dog.play();
System.out.println("----------------");
Factory f2=new CatFactory();
Animal cat = f2.createAnimal();
cat.play();
}
}
運行結果:
狗喜歡玩泥巴...
---------------
貓喜歡玩泥鰍...
----------------
貓喜歡玩泥鰍...
設計模式之單例模式
單例模式核心思想:某些類的對象在創建的時候 ,在系統內存始終只有一個對象!
單例模式分類:
1)餓漢式 2)懶漢式(類似於多線程環境..)
兩種分類在設計上幾乎一樣:
1)定義個類,將該類的無參構造方法私有化
2)在該類的成員位置創建該類對象 並且一定要私有化,防止外界更改這個對象
3)在該類中提供靜態成員方法(返回值就是創建的那個對象),能被當前類直接調用,static修飾
我們先來看看餓漢式:
package com.westos_03;
public class Student {
/*
//創建學生類無參構造
public Student() {
}
*/
//進行改進
//創建私有化學生類無參構造,目的是不讓它創建對象
private Student() {
}
//創建學生類對象,因爲下面的方法是靜態的,返回了s,所以創建學生類對象時也得添加static
private static Student s=new Student();
//創建學生類方法,添加static可以直接用類名調用方法
public static Student getStudent() {
return s;
}
}
package com.westos_03;
/**
* @author 傑哥
*
*餓漢式:
* 在加載那個類的時候,對象的創建工作就已經完成了!
*
*優點:線程是安全的,加載類時對象已經創建好了,而且不會在變
*缺點:無論需不要,只要加載類就會創建對象,在內存上有點浪費多餘
*/
public class StudentDome {
public static void main(String[] args) {
/*
//創建學生類對象
Student s1=new Student();
Student s2=new Student();
System.out.println(s1==s2);//運行結果:false
*/
/**
* 當我們給學生對象賦值爲null時
* s1,s2的運行結果都是null
* 爲了防止外界隨意更改數據我們應該在創建學生類時讓它私有化
*/
// Student.s=null;
Student s1 = Student.getStudent();
Student s2 = Student.getStudent();
System.out.println(s1==s2);
System.out.println(s1);
System.out.println(s2);
}
}
運行結果:
true
com.westos_03.Student@70dea4e
com.westos_03.Student@70dea4e
讓我們再來看看懶漢式:
懶漢式:
符合單例模式核心思想
1)自定義一個類,將無參構造私有化
2)在成員位置聲明變量
3)提供公共靜態功能,在裏面判斷的創建該類對象,返回該類對象
如果是開發中,那麼就使用餓漢式(餓漢式它不會出現問題的單例模式)
如果是面試中,那麼使用懶漢式(因爲他是可能出現問題的一種單例模式)
面試題:
你使用過單例模式嗎?簡單介紹一種單例模式,請用代碼設計
面試官想問的是:使用設計單例的懶漢式,能否想到使用同步機制解決線程的安全問題..
懶漢式(延遲加載 -->懶加載)
可能會出現問題
---> 多線程的問題
1)是否是多線程環境
2)是否有共享數據
3)是否有多條語句對共享數據進行操作 (使用同步機制進行操作)
例如:
package com.westos_03;
/**
* @author 傑哥
*懶漢式與餓漢式的相同在於:
* 創建私有無參構造
* 創建私有類對象
* 創建公共靜態方法
*
*不同之處在於:
* 餓漢式隨着該類的加載會一直創建類對象
* 懶漢式會根據需求來創建類對象
*/
public class Teacher {
//創建私有Teacher類無參構造
private Teacher() {
}
//創建私有變量,先賦值爲null
private static Teacher t=null;
/*
//創建公共靜態方法
public static Teacher getTeacher() {
//加入同步鎖
synchronized(Teacher.class) {
if(t==null) {
t= new Teacher();
}
return t;
}
}
*/
public synchronized static Teacher getTeacher() {
if(t==null) {
t=new Teacher();
}
return t;
}
}
package com.westos_03;
public class TeacherDome {
public static void main(String[] args) {
Teacher t1 = Teacher.getTeacher();
Teacher t2 = Teacher.getTeacher();
System.out.println(t1==t2);
System.out.println(t1);
System.out.println(t2);
}
}
運行結果:
true
com.westos_03.Teacher@70dea4e
com.westos_03.Teacher@70dea4e
每個 Java 應用程序都有一個 Runtime 類實例,使應用程序能夠與其運行的環境相連接。
public static Runtime getRuntime()返回與當前 Java 應用程序相關的運行時對象
public Process exec(String command)
throws IOException在單獨的進程中執行指定的字符串命令。
例如:
package com.westos_03;
import java.io.IOException;
public class RuntimeDome {
public static void main(String[] args) throws IOException {
//常見RunTime類實例
Runtime rt=Runtime.getRuntime();
//開啓某一個進程
rt.exec("calc");
rt.exec("notepad") ;
rt.exec("mspaint") ;
}
}