简单地设计模式

设计模式包括很多原则,但是学习他我们要先从类图等uml的东西去了解他。

 

那就先开始学习uml里面的类图。

  类图:

 1 类之间的几种关系:1 泛化

2 实现

3 关联:一般联合,聚合,组合。

4 依赖

 

2 类图中的类:包括三个东西,分别是名称(name.属性().操作(function)。

3 接口:两行。

4 类之间的几种关系:就是第一点要指出的。

(1) 泛化:指继承。用子类指向父类,实线,空三角。 父类   <← 子类,和这个比较类似,但是图库资源有限,只好先这样

(2) 实现:指实现接口。用实现类指向接口,虚线,空三角。

(3) 一般关联:比如老师和学生。没有什么大的关联,但是有一些。用一条没有箭头的实线就好。

(4) 聚合:整体与部分,且整体与部分分离,部分能单独存在。比如汽车与轮胎。用部分指向整体,且为实线,空菱形。

(5) 组合:整体与部分,且整体与部分分离,部分不能单独存在。比如公司与部门,部门与小组。用部分指向整体,且为实线,实心菱形。

(6) 依赖:其实任何事物都有依赖,所以一般也不会用到这层关系。

 

这些关系可以做大小比较:泛化=实现>组合>聚合>关联>依赖。

 

 

工厂模式

这次要学习工厂模式,工厂模式是用来new 一个对象,一般new对象都要在main这种主方法里面,

如果要是new 56个对象,那么一个main就要依赖56个类。并且还需要知道类名,导致消息的泄露。因此就有了工厂模式,工厂模式是生产对象的工厂

工厂模式包括三种:简单工厂模式,工厂模式,抽象工厂模式。

简单工厂模式:一个工厂类,里面有一个静态方法,可以创建对象,其中根据传入的参数不同就可以new不同的对象,如果可以的话,可以直接通过先解析xml或者properties,然后利用反射(class.forname())去创建类,然后再getinstance,这样就可以创建对象。如果改变对象,只需要改变对象的xml或是properties

重:其中用到一个知识点:父类对象可以被子类对象替代。比如:class Aclass B的父类,则可以

A a=new B();这样是可以的。

工厂模式:为了解决简单工厂模式的不符合开毕原则(开毕原则:即可以添加代码,尽量不去修改代码),由于要想新建对象,简单工厂模式实际上是需要修改以前的工厂代码的(比如要添加一个类),所以为此我们需要创建一个工厂接口,一种商品就继承一个接口,比如要一个电视接口,那么以前是就一个工厂,判断需要哪个对象就new 哪个对象,如果是工厂模式,则海尔电视一个工厂,海信电视一个工厂,这样,如果再增加一个tcl电视,那么继承电视接口添加代码就好,如果是以前,则就会需要改变工厂类的代码,去再添加一个tcl电视的判断。

接着就是抽象工厂模式

首先:简单工厂模式:可以生产任何产品。

      工厂模式:只可以生产一种产品。

 抽象工厂模式:一个工厂可以生产多个商品:比如电脑需要生产cpu 键盘 鼠标 显示器 显卡等。

抽象工厂模式首先也需要一个工厂接口,然后可以两个厂子去继承他(比如海尔与海信),然后再里面鼓捣,这和工厂模式是一样的,区别就是工厂模式只new一个东西,比如电脑(new computer()),而这里面需要new 好几个,比如(new cpu(),new 键盘(),new 显卡())。区别就在这里。实际上是差不多的。

下面讲单例模式:单例模式的目的是就是让整个程序里只有一个实例,比如我们所熟知的windows操作系统,如果你打开记事本这个软件,你可以打开n次,如果你打开资源管理器,你会发现无论你打开多少次,都会只产生一个资源管理器。

单例模式写的时候一定注意1个地方:1 构造器一定要private(这样就不能new 这个class.

单例模式包括两种情况:1 饿汉模式 2 懒汉模式

1 饿汉模式:顾名思义,特别饿,所以只要一加载类(即把类放任jvm(把.java转化为.class)),就要生成这个属性(而且为了可以不被再建立属性,一定要添加static),但是这样就会时间换空间(static占据空间,但是一加载类就生成(节省时间))

2 懒汉模式:就是特别懒,需要的时候才需要去new 所以要先判断有没有这个实例,然后才new,注意这里一定要注意线程安全,因为如果但时有两个线程去请求这个,一个线程判断空,此时切换到另一个线程,另一个线程判断不为空,此时又切换到原来那个线程,原来那个线程就是认为他会不为空,结果就不去创建线程,导致错误,此时就会需要synchronized,这样就会保护代码段。

3 序列化和反射会破解这个单例模式。反破解。

 

懒汉式:

Class b{

Private static b ins;

Private b(){}

Public static synchronized getins(){

If(ins!=null){

Ins=New b();

Return ins;

    }

  }

}

饿汉式:

Class a{

private static a instance=new a();

Private a(){}

Public static getins(){

Return instance;

}

}

 

 

 

 

建造者模式

这堂课我们来学习建造者模式:

这个模式是非常重要,但是却有点复杂。他也是创建新的对象的模式。

需要四个原料:1 产品(product) 2 建造者接口(abstract builder) 3 建造者类(builder) 4 服务员类(director

产品:比如生产一个汽车。(他包括车轮 座椅 发动机)。

建造者接口:这里必须要有建造这个的方法:craetetyre(); createengine(); createseat();

建造者类:实现这些方法。

服务员类(这个名字自己起的,有可能不到位):在这里面把建造车的方法都封装在一起,这样client里面就可以直接调用这个方法而不是一个一个使用建造的方法。

 

上代码:现在就把所有的放到一起,但是会拿--------------------(线)去分隔

 

 

 

 

原型模式

这次我们学习原型模式,他仍然是一个创建型模式。用来创建对象,其中分为深克隆还有浅克隆,二者的区别是浅克隆只克隆名字(即对象),而深克隆克隆所有,这个需要自己体会。

下来我们先来学习浅克隆

 

浅克隆:

重中之重:三个条件:

1 实现cloneable接口

2 重写clone方法。(必须有super.clone()

3 return clone

剩下的只是需要new 就好

代码:

服务器:package clonedesign;

public class cloneexamp implements Cloneable {

//需要一个变量,并定义

private String name;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

//这时cloneable只是一个标示,和serelizable是一样的

protected Object clone() throws CloneNotSupportedException {

// TODO Auto-generated method stub

return super.clone();

}

}

这是客户端:

public class client {

public static void main(String[] args) {

cloneexamp clone1=new cloneexamp();

clone1.setName("lc");

cloneexamp clone2=null;

try {

clone2 = (cloneexamp) clone1.clone();

} catch (CloneNotSupportedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(clone1==clone2);

System.out.println(clone2.getName());

}

}

输出:false lc

注:我们克隆啥,啥的地址就会成为新的,意思是就像上一个例子,克隆对象,则对象不一样,输出false,而指向的空间不变,因此都指向namelc的空间,而如果此时把name这个属性也克隆,那么就不会输出lc。因为name有了新地址。

深克隆:

一定要完成三点:

1 实现serializable接口。

2 创建deepclose()方法(自己创建的,你应该知道serializable不需要实现任何方法)。

3 deepclone()里面一定要序列化,反序列化(即inputstream outputstream

我本人不觉得深克隆比较好。

深克隆是复制所有,即所有东西克隆后都不一样,所有都有了新的东西。

所以我比较喜欢浅克隆。

重重重重重重:那么克隆是干啥的,为啥要用它

克隆一点:不管深克隆还是浅克隆,创建的速度都要比new强大很多倍。如果这个class很简单,那么或许new快一些,如果class复杂,并且需要五十万个对象,你可以试试,克隆会比new快不知道多少倍

浅克隆又一点:电脑上的复制粘贴用的就是浅克隆,一个word文档复制之后,那么对象地址变了,指向的内容一样,这样很节省空间。

 

 

 

 

适配器模式

这次我们学习适配器模式:

适配器模式就是adapter1,最简单的就是比如:德国的插座只能插两个,并且两个比较厚圆,而中国的可以插三个,且是扁头,

这个时候就需要适配器。

重中之重:适配器模式是啥:就是比如有两个东西A,B,这个随便,适配器C必须把二者关联起来,不管二者是啥。为此有两种方法:一种是对象适配器模式,另一个是类适配器模式。

所以其实适配器就需要三个A B C.

使用的情况是啥?人们说让B继承A,这样不符合情况,比如已经写好了机器人类和狗类,并且想让二者有关联,这时如果让狗继承机器人,显然要修改代码,违反开闭原则,况且狗已经继承了动物类呢,单继承是不能再继承的。

上代码:

类适配器模式:代码附adapter文件夹。

桥接模式:

1 这次讲的是桥接模式。

桥接模式,是在已经有很多东西的时候添加的。

比如:生产电脑,电脑是一个接口,而电脑的型号是平板,笔记本,台式,所以这三个要实现电脑接口,但是,不光如此,电脑还是有品牌的,即苹果的电脑(台式,平板,笔记本),还有可能是索尼的(平板电脑,台式电脑,笔记本电脑)。当然还有可能是小米的。

那么按照普通的模式来说,则是这么写:

interface computer{

void sale();

}

//台式

class pc implements computer{

void sale(){

System.out.println("this is pc");

}

}

//笔记本

class laptop implements computer{

void sale(){

system.out.println("this is laptop");

}

}

//平板

class pad implements computer{

void sale(){

System.out.println("this is pad");

}

}

 

class hasee extends pc{

void sale(){

System.out.println("this is hasee pc");

}

}

 

class hasee extends Laptop{

void sale(){

System.out.println("this is hasee laptop");

}

}

 

class hasee extends pad{

void sale(){

System.out.println("this is hasee pad");

}

}

 

class sony extends pc{

void sale(){

System.out.println("this is sony pc");

}

}

 

class apple extends pc{

void sale(){

System.out.println("this is apple pc");

}

}

这么写的后果是什么,比如现在已经有了苹果电脑,我需要在增加一个品牌,比如联想,那么需要写三个类,即(class lenovopc extends pc,class lenovopad extends pad ,class lenovo extends laptop;如果是不这么写的话,那么是这样,需要一个品牌的接口,以下是代码:

 

 

package designpatttern;

 

public abstract class computer {

//abstract 不只有方法(没有实现的),也可以有实现的方法,也可以属性。

private Brand brand;

 

public computer(Brand b){

this.brand=b;

this.brand.isbrand();

}

 

 

abstract void sale();

}

 

class pc extends computer{

 

public pc(Brand b) {

super(b);

// TODO Auto-generated constructor stub

}

 

@Override

void sale() {

// TODO Auto-generated method stub

System.out.println("这是台式电脑");

}

 

}

 

class pad extends computer{

 

public pad(Brand b) {

super(b);

// TODO Auto-generated constructor stub

}

 

@Override

void sale() {

// TODO Auto-generated method stub

System.out.println("这是平板");

}

 

}

 

class laptop extends computer{

 

public laptop(Brand b) {

super(b);

// TODO Auto-generated constructor stub

}

 

@Override

void sale() {

// TODO Auto-generated method stub

System.out.println("这是笔记本");

}

 

}

-------------------------------------------------------------------------------------------------------------------------这是品牌

package designpatttern;

 

public interface Brand {

void isbrand();

}

 

class lenovo implements Brand{

 

@Override

public void isbrand() {

// TODO Auto-generated method stub

System.out.println("这是联想");

}

 

}

 

class apple implements Brand{

 

@Override

public void isbrand() {

// TODO Auto-generated method stub

System.out.println("这是苹果");

}

 

}

 

class sony implements Brand{

 

@Override

public void isbrand() {

// TODO Auto-generated method stub

System.out.println("这是索尼");

}

 

}

这种情况的好处显而易见:即比如需要一个新的品牌(比如华硕),则只需要写一段代码,即一个class(class 华硕 implements Brand)

极大的节省了代码。

 

 

 

 

装饰者模式

这次学习装饰者模式:

主要用处就是:

1 避免了不能多继承所带来的不变。即如果一个车能在地面上跑,子类有飞的功能,子类有在水里开的功能,子类还有自动驾驶的功能,这三个功能是三个类,这三个类分别继承地面上跑的功能,如果还有一个车既要飞,也要在水里就不好了,因为,不能继承两个父类,

聪明的你应该想到了对策。

2 对策就是继承,只不过,B继承A,C继承B,这三者通过super关键字在叠加操作,

 

代码:

interface Icar{

public void move();

}

 

final class car implements Icar{

public void move(){

SYstem.out.println("能在地上跑");

}

}

 

class supercar implements Icar{

 

protected Icar car;

 

public supercar(Icar car){

super();

this.car=car;

}

 

public void move(){

car.move();

}

 

}

 

 

class flycar extends supercar{

 

public flycar(Icar car){

super(car);

}

 

public void fly(){

System.out.println("可以飞的车");

}

 

public void move(){

super.move();

this.fly();

}

}

 

class swimcar extends supercar{

 

public swimcar(Icar car){

super(car);

}

 

public void swim(){

System.out.println("可以游泳的车");

}

 

public void move(){

super.move();//上一个的所有再加上这一个的新方法

this.swim();

}

}

 

class AIcar extends supercar{

 

public swimcar(Icar car){

super(car);

}

 

public void AI(){

System.out.println("可以自动驾驶的车");

}

 

public void move(){

super.move();

this.AI();

}

}

 

 

class client{

 

public static void main(String []args){

 

 

System.out.println("-------------------");

Icar car=new Car();

car.move();

 

System.out.println("-------------------");

car=new flycar(car);

car.move();

 

System.out.println("-------------------");

car=new swim(car);

car.move();

 

System.out.println("-------------------");

car=new AIcar(car);

car.move();

 

}

}

 

 

最经典的用法就是javaio流,

BUfferedReader bur=new BufferedReader(new InputStreamReader(new FileInputStream(“./a.txt”)));

 

 

 

重重重重:super.move(),这里指的是应该是父类的move()也就是supercarmove()方法,里面实现了car.move();这个car.move()中的car是所传递过来的car对象(这个对象就是this.car=car,因此就是传递过来的对象的move()),这样新的move()就包括了两个,即super.move()和新的方法,比如this.swim(),这样吧他们打包生成新的move(),这样又会被叠加,也就造成了叠加。所谓的装饰器就是把move这个方法和其传过来的对象对应上。然后每次都有新的方法从而导致了叠加。

叠加要满足两点:1 装饰器的方法里面的构造器的对象要和其方法对应上。

     2 方法的叠加move()里面要嵌套一个super.move()

多写写就会了。

外观模式:

外观模式很好理解,其实就是一层封装,

比如:你要喝茶,需要先准备茶杯,接着准备茶叶,然后烧水,再就是准备泡茶,那么现在有好几个人,张三,李四,王五,他们每个人喝茶都要完成这么多类,完成这么多方法,那么此时就需要一个服务员,如果服务员把所有的事都做好,那么我们需要做的事就是把服务员叫过来,然后让他做好茶,我们直接喝,其实就是一个封装的问题。

 

 

享元模式

这次我们学习享元模式。

解决问题:比如说下围棋,我们一般围棋有很多棋子,比如黑色棋子100个,白色棋子100个,首先声明黑色棋子,因为每个黑棋子的位置不同(虽然颜色相同),所以按照以前的做法肯定是声明100个对象,那么这样会大大的浪费内存资源,但是我们想一想,其实他们的颜色相同,只是位置不同,那么其实如果只是声明一个对象就可以。

思路:就是分为两个类,一个类做公有的东西(颜色),另一个就是做私有的东西(位置)

代码如下:

 

package chessflyweight;

 

import java.util.HashMap;

import java.util.Map;

 

public interface chessflyweight {

 

void display(coordinate c);

}

 

class concreteChess implements chessflyweight{

 

 

private String color;

 

public String getColor() {

return color;

}

 

public void setColor(String color) {

this.color = color;

}

 

@Override

public void display(coordinate c) {

// TODO Auto-generated method stub

System.out.println("位置为:x-"+c.getX()+"y-"+c.getY());

System.out.println("颜色为:"+this.color);

}

}

 

class coordinate{

 

private int x;

private int y;

 

public coordinate(int x,int y){

this.x=x;

this.y=y;

}

 

public int getX() {

return x;

}

public void setX(int x) {

this.x = x;

}

public int getY() {

return y;

}

public void setY(int y) {

this.y = y;

}

 

}

 

 

class chessFlyWeightFactory{

 

private static String color;

 

public chessFlyWeightFactory(String color){

this.color=color;

}

 

private static Map<String,chessflyweight> map=new HashMap<String,chessflyweight>();

 

//静态变量的获得需要静态方法

public static chessflyweight getchess(){

if(map.get(color) != null){

return map.get(color);

}else{

//就要声明这个对象了

chessflyweight cfw=new concreteChess();

map.put(color, cfw);

return cfw;

}

}

}

其实就是把对象放到一个map里面,如果存在这个对象,则直接get这个对象,没有则创建这个对象,并pushmap里面,并且由于每个棋子的位置不同,则每次创建的位置可以不同。但是对象一样。即棋子只需创建一个,我们只是需要报告他的位置,即其中有一个参数不同,但是他的对象都一样。

 

 

 

 

posted @ 2017-05-07 16:45  freebirds  阅读(212)  评论(0)    收藏  举报