很多人在学习设计模式,感觉定义很抽象,包括我,这也难怪JAVA本来就是一种抽象的思想,所以写了这篇博客,加入我自己的理解,难免会有一些不合理的地方,希望大家批评指正。
首先说说设计模式是什么吧。简单的来说,设计模式是一个经验的总结,与具体的语言无关,相当于一个模型,可以被不同的语言反复使用,本文以JAVA语言为基础。
一、要明白具体的设计模式,我们就需要知道设计模式做了什么,具体原则是什么
1. 单一职责:简单的说,就是每个类需要做的事情尽量少,最好是一件
2. 开闭原则:把经常变得东西抽象成一个模板,变化的部分只提供一个方法,具体的细节由子类实现,即别人想添加功能,只需要添加一个子类,而无需修改源码的实现。
3. 里氏替换:这个我们应该很熟悉,就是一种继承的理念,即继承父类的子类们中,应该具有一些共同的行为特征和属性,比如不能定义一个Person类,让Pig继承。
4. 依赖注入原则:也是一种分离思想,即子类对象依赖于抽象类,而不是依赖具体实现类
5. 接口分离原则:一个接口的功能要满足单一原则,因为接口的实现,必须重写接口的方法,所以接口的抽象方法不宜过多。
6. 迪米特原则:对象与对象之间的关系要少,比如一个对象尽量不要去调用另一个对象的方法。
7. 总结,虽然是用自己的话在表述,但自己也不知道自己在写什么。
二、接下来,我想介绍一些常用的设计模式
█ 简单工厂设计模式:类的创建由工厂类去实现,比如我需要实现一个水果工厂,别人需要什么水果,我就提供什么
第一步:创建工厂类
public class FruitFactory {
public static Fruit createFruit(String fruitType)
{
if("apple".equals(fruitType)){
return new Apple();
}else if("banana".equals(fruitType))
{
return new Banana();
}else{
return null;
}
}
}
第二步:水果接口
public abstract class Fruit {
public abstract void taste();
}
第三步:创建需要添加的具体水果
1. 造苹果
public class Apple extends Fruit {
@Override
public void taste() {
// TODO Auto-generated method stub
System.out.println("苹果味道有点酸!");
}
}
2. 造香蕉
public class Banana extends Fruit {
@Override
public void taste() {
// TODO Auto-generated method stub
System.out.println("香蕉味道很甜!");
}
}
第四步:具体实现造水果
public class FruitDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Fruit fruit = FruitFactory.createFruit("apple");//要苹果?造一个!
fruit.taste();
a = AnimalFactory.createAnimal("banana");//要香蕉?造一个!
fruit.taste();
}
}
第五步:总结
从上面的代码,得知,水果工厂内只有apple和banana,但如果客户需要橘子,怎么办?这还不简单?so easy。
public class FruitFactory {
public static Fruit createFruit(String fruitType)
{
if("apple".equals(fruitType)){
return new Apple();
}else if("banana".equals(fruitType))
{
return new Banana();
}else if("orange".equals(fruitType))
{
return new Orange();
else{
return null;
}
}
}
但还需要橙子,梨子,桃子呢?所以缺点总结如下
1. 有新的需求,工厂类就必须不断修改,麻烦!所以出现了工厂类。下面介绍工厂类。
█ 工厂模式:在简单工厂类的基础上,添加了小工厂,就好像有一个水果工厂,还添加一个子工厂,专门造苹果,另一个子工厂专门造香蕉,这样,新的需求只需添加一个需求类实现水果工厂接口即可,废话不多说,看代码。
第一步:创建大工厂类接口
public interface Factory {
public abstract Fruit createFruit();
}
第二步:创建水果类
public abstract class Fruit {
public abstract void taste();
}
第三步:创建具体水果的小工厂类,实现大工厂接口
1. 苹果工厂
public class AppleFactory implements Factory {
@Override
public Fruit createFruit() {
// TODO Auto-generated method stub
return new Apple();
}
}
2. 香蕉工厂
public class BananaFactory implements Factory {
@Override
public Fruit createFruit() {
// TODO Auto-generated method stub
return new Banana();
}
}
第四步:造水果,继承水果类
1. 造苹果
public class Apple extends Fruit {
@Override
public void taste() {
// TODO Auto-generated method stub
System.out.println("苹果味道有点酸!");
}
}
- 造香蕉
public class Banana extends Fruit {
@Override
public void taste() {
// TODO Auto-generated method stub
System.out.println("香蕉味道很甜!");
}
}
第五步:测试类
public class FruitDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//苹果
Factory factory = new AppleFactory();
Fruit fruit = factory.creatFruit();
System.out.println(fruit.taste);
//香蕉
factory = new BananaFactory();
Fruit fruit = factory.creatFruit();
System.out.println(fruit.taste);
}
}
第六步:总结
优点:每增加一个需求,只需增加一个具体类,和具体类的工厂类,而无需改动原有的代码。
缺点:工作量较大,看着都累。
█ 单例设计模式:简单的来说,就是不允许外部创建对象,而是直接使用,那么如何实现不让外界创建对象,而且还可以使用对象呢?
- 将被使用类的构造方法私有化,即private修饰
- 在类的成员位置创建对象
- 创建公有方法getObject,让外界能够使用
- 单例设计模式——-饿汉式:就是立即创建对象
public class Fruit {
private Fruit()
{
//构造方法使用private修饰
}
//创建Fruit对象
static Fruit fruit = new Fruit();
//通过公有属性方法返回对象给外界
public static Fruit getFruit()
{
return fruit;
}
}
测试
public class FruitDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Fruit.fruit = null;
Fruit fruit = Fruit.getFruit();
}
}
- 单例设计模式——-懒汉式:不立即创建对象,而是延后到被调用时
public class Fruit {
private Fruit()
{
//构造方法使用private修饰
}
//创建Fruit对象
static Fruit fruit = null;
//通过公有属性方法返回对象给外界
public static Fruit getFruit()
{
if(fruit == null)
{
fruit = new Fruit();
}
return fruit;
}
}
测试
public class FruitDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Fruit.fruit = null;
Fruit fruit = Fruit.getFruit();
}
}
- 单例设计模式——总结
在实际应用中会选择饿汉式,因为懒汉式存在安全隐患,在多线程时,多个线程同时获取该对象时,会出现对象具体的创建混乱。解决办法如下:同步方法。
public class Fruit {
private Fruit()
{
//构造方法使用private修饰
}
//创建Fruit对象
static Fruit fruit = null;
//通过公有属性方法返回对象给外界,注意添加synchronized,实现线程的同步
public synchronized static Fruit getFruit()
{
if(fruit == null)
{
fruit = new Fruit();
}
return fruit;
}
}
█ 模版设计模式:定义一个算法的骨架,这个骨架就是一个模版,具体的算法实现推迟到子类中,比如我们计算算法运行的效率,我们就可以把计算效率提取成一个模版,而具体的算法我们可以到子类中实现,而无需改动模版。
第一步:定义一个模版
public abstract class Pattern {
public long getTime(){
long startTime = System.currentTimeMillis();
methodPattern();//只需实现这个抽象方法来实现具体的算法即可
long endTime = System.currentTimeMillis();
return endTime-startTime;
}
public abstract void methodPattern();
}
第二步:实现具体的算法,这里选择快速排序,其他的就不一一举例
public class ForTest extends Pattern {
//排序
public static void Sort(int[] arr,int low,int high)
{
if(low < high)
{
int position = getPositionSort(arr,low,high);
Sort(arr,low,position-1);
Sort(arr,position+1,high);
}
}
private static int getPositionSort(int[] arr, int low, int high) {
// TODO Auto-generated method stub
int temp = arr[low];
while(low < high)
{
while(low < high && arr[high]>temp)
high--;
arr[low] = arr[high];
while(low < high && arr[low] < temp)
low++;
arr[high] = arr[low];
}
arr[low] = temp;
return low;
}
//主要是这个构造方法的重写
@Override
public void methodPattern() {
// TODO Auto-generated method stub
int arr[] = {12,3,2,30,10};
Sort(arr,0,arr.length-1);
for(int s_arr:arr)
{
System.out.print(s_arr+" ");
}
}
}