#
代码:
基本:
/Files/jokes000/Singleton.txt 单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但不能防止你实例化多个对象。一个最好的方法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
单例模式因为Singleton类封装它的唯一实例,这样它可以严格地控制客户怎样访问它以及何时访问它。
注意:!!!
多线程程序中,多个程序同时,注意是同时!访问Singleton类,调用GetInstance()方法,会有可能造成创建多个实例。
代码:
基本:
组合模式(Composite):将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
什么时候使用?
需求中是体现部分与整体层次的结构,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑使用组合模式了。
优点:
组合模式定义了包含基本对象和组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了。
用户不用关心到底是处理一个叶节点还是处理一个组合组件,也就用不着为定义组合而写一些选择判断语句了。组合模式让客户可以一致的使用组合结构和单个对象。
结构图:
代码:
基本:
/Files/jokes000/Memento.txt 备忘录(Memento)模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原来保存的状态。
什么时候用?
Memento模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性指示众多属性中的一小部分时,Originator可以根据保存的Memento信息还原到前一状态。
结构图:
代码:
实例:
/Files/jokes000/Adapter.rar 基本:
Adapter 适配器模式:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的类可以一起工作。
什么时候使用?
主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。(姚明--英语翻译)
结构图:
代码:
实例:
基本:
/Files/jokes000/State.txt 状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。
优点:
将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。
(消除庞大的条件分支语句) 将特定的状态相关的行为对放入一个对象中,由于所有与状态相关的代码都存在于某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。
状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互间的依赖。
什么时候使用?
当一个对象的行为取决于它的状态,并且它必须在运行时根据状态而改变它的行为时,就可以考虑使用状态模式了。
结构图:
抽象工厂模式(Abstract Factory):提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类。
结构图:
AbstractFactory:抽象工厂接口,它里面应该包含所有的产品创建的抽象方法。
AbstractProductA、AbstractProductB:抽象产品,它们都有可能两种以上不同的实现。
优点:
最大的好处便是易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体的工厂分离实现,不会出现在客户端代码中。
缺点:
若需要新增加一个ProductC,需要增加很多类,以及修改相应很多类。
解决方案:反射+抽象工厂模式。
代码:
基本:
Code
/* 观察者类:
* 它把所有对观察者对象的引用保存在一个聚集里,
* 每个主题都可以有任何数量的观察者。抽象出题
* 提供一个借口,可以增加和删除观察者对象
*/
class Subject
{
private:
List<Observer> observers;
public:
// 增加观察者
void Attach(Observer observer)
{
observers.add(observer);
}
// 移除观察者
void Detach(Observer observer)
{
observers.remove(observer);
}
// 通知
void Notify()
{
foreach( Observer o in observers )
{
o.Update();
}
}
};
/* Observer类,抽象观察者
* 为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
* 这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口
* 实现。更新接口通常包含一个Update()方法。
*/
class Observer
{
public:
virtual void Update();
};
/* ConcreteObserver类:
* 将有关状态存入具体观察者对象;在具体主题的内部状态改变时,
* 给所有登记过的观察者发出通知。具体主题角色通常用一个具体
* 子类实现。
*/
class ConcreteSubject : public Subject
{
private:
string subjectState;
public:
//get-set方法;
};
/* ConcreteObserver类:
* 实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题
* 的状态相协调。具体观察者角色可以保存一个指向具体主题对象的
* 引用。具体观察者角色通常用一个具体子类实现。
*/
class ConcreteObserver : public Observer
{
private:
string name;
string observerState;
ConcreteSubject *subject;
public:
ConcreteObserver(ConcreteSubject& subject, string name)
{
this->subject = subject;
this->name = name;
}
virtual void Update()
{
observerState = subject->subjectState;
// do something..
}
// Concretesubject的get、set方法
};
// 客户端代码
int main()
{
ConcreteSubject *s = new ConcreteSubject();
s->Attach(new ConcreteObserver(s,"X"));
s->Attach(new ConcreteObserver(s,"Y"));
s->setSubject("ABC");
s.Notify();
观察者模式:又称发布-订阅(Publish/Subscribe)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
观察者模式的动机是什么:
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
什么时候使用观察者模式:
当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,应考虑使用观察者模式。
一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们相互独立地改变和服用。
总体来讲,观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
结构图:
A. C风格类型转换就像粗鲁的野兽,可以通过它们在任意类型之间进行转换。如果能够更明确地指定每个转换的目的,可能会更好。
B. C风格类型转换很难进行查找。
C++通过引入4种新的类型转换操作符客服了C风格的类型转换的缺点。这4种操作符是:
1.static_cast: 与通用的C风格类型转换,基本上有着同样地能力和意义。
static_cast
int firstNum,secondNum;
double result = ((double)firstNum)/secondNum;
// 使用新的类型转换,应该这样写:
double result = static_cast<double>(firstNum)/ 2.const_cast: 最常用法,去除掉一个对象的const属性。
3.dynamic_cast: 用来针对一个继承体系做向下或者横向的安全转换。
dynamic_cast
// SpecialWidget继承于Widget
Widget *pw;
update( dynamic_cast<SpecialWidget*>(pw) );
// fine, passes to update a pointer
// to the SpecialWidget pw points to
// if pw really points to one,
// 4.reinterpret_cast: 最常见用法是在函数指针之间进行类型转换。
连接数据库步骤:(以MySql为例)
1.注册驱动:Class.forName("com.mysql.jdbc.Driver");
2.建立连接:Connection conn = DriverManager.getConnection( url , user , password );
url格式: jdbc:子协议:子名称://主机名:端口/数据库名?属性名=属性值&...
String url = "jdbc:mysql://localhost:3306/jdbc";
// 若主机名及端口号均为缺省值,则可省略掉,如String url = "jdbc:mysql:///jdbc";
3.创建语句:PreparedStatement
4.执行语句:executeQuery(), executeUpdate()
5.返回结果:ResultSet
6.释放资源:
PreparedStatement相对于Statement的优势:
1.没有SQL注入的问题
2.Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出
3.数据库和驱动可以对PreparedStatement进行优化(只有在相关联的数据库连接没有关闭的情况下有效)
数据库连接池概念:
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
使用数据源和JNDI API:
1.Java EE 应用程序服务器提供了命名空间,可以使用 JNDI API 来访问命名空间。
2.Java EE 应用程序服务器必须支持在 JNDI 命名空间中存储数据源资源。
3.数据源是封装连接数据库的所需信息的对象:
A.数据库 URL
B.驱动程序
C.用户名和密码
4.大部分服务器提供了使用数据源访问的数据库连接池。
在tomcat中配置JNDI步骤:
1.找到tomcat中server.xml文件,在其中加入以下代码
Server.xml
<Context path="/ViewDemo">
<Resource
name="jdbc/leagueDB"
type="javax.sql.DataSource"
driverClassName="org.gjt.mm.mysql.Driver"
maxIdle="2"
maxWait="5000"
username="root"
password="root123"
url="jdbc:mysql://localhost/league"
maxActive="4"/>
</Context> 2.在项目的web.xml文件中,加入以下代码:
web.xml
<resource-ref>
<description>
This defines a JNDI resource reference for
java:comp/env/jdbc/leagueDB DataSource which
is formally declared in the domain.xml.
</description>
<res-ref-name>jdbc/leagueDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref> 3.将JDBC驱动放入tomcat/lib目录当中
有连接池的情况下,connection.close()不是关闭连接,而是将连接设置为available状态。