A general idea as to how this can be done in a consistent way is explained in the help documents under NonCommutativeMultiply. The thing is that you want to use your operators in an algebraic notation, and that's what that page discusses.
If, on the other hand, you're happy with a more formal Mathematica notation, then you would have the easier task of defining operators simply as
dx := D[#, x] &
dy := D[#, y] &
and using them as follows:
dx@f[x, y, z]
$f^{(1,0,0)}(x,y,z)$
Combining operators would then be done using Composition:
dxy = Composition[dx, dy];
dxy[f[x, y, z]]
$f^{(1,1,0)}(x,y,z)$
Edit
Here is another approach that's sort of intermediate between the very simple D[#,x]& scheme and the more complicated realization of an operator algebra in the linked reference from the documentation.
To make the operators satisfy the axioms of a vector space, we'd have to define their addition among each other and the multiplication with scalars. This can be done most conveniently if we don't use patterns to represent the operators, but Functions. So here I repeat the operator definitions - they act the same way as the dx, dy defined above, but their definition is stored differently:
dx = Function[{f}, D[f, x]];
dy = Function[{f}, D[f, y]];
Now I define the multiplication of an operator with a scalar:
multiplyOp[scalar_, op_] := Function[{f1}, scalar op[f1]];
For simplicity, I always assume that the scalar is given as the first argument, and the second argument is an operator, e.g., dx etc. Note that the arguments here are not x or y (the assumed independent variables on which functions depend), because multiplyOp maps operators onto operators.
Finally, we need the addition of two (or more) operators, which is again a mapping from operators (a sequence of them) onto operators:
addOps[ops__] := Function[{f1}, Total@Map[#[f1] &, {ops}]];
Both addition and multiplication are mapped back to their usual meaning in these functions, by defining how the combined new operators act on a test function f1 (which is in turn a function of x, y, and z - depending on the dimension).
To illustrate the way these operations are used, take the example in the question,
$\left(\partial_x+\partial_y+z\right)x\psi$
and write it with our syntax:
addOps[dx, dy, multiplyOp[z, Identity]]@(x ψ[x, y])
$x \psi ^{(0,1)}(x,y)+x \psi ^{(1,0)}(x,y)+\psi (x,y)+x z \psi (x,y)$
This is the correct result (the result quoted originally in the post was actually missing an x).
Note how I added the scalar z above: in this syntax, it first has to be made into an operator using multiplyOp[z, Identity]. The Identity operator is very useful for this.
Of course these expressions with addOps and multiplyOp aren't as easy to read as the ones with simple + signs, but on the bright side it can also be beneficial pedagogically to separate the "operator operations" clearly from the operations between the functions they act on.
Edit 2
In response to the comment, I'll add a nicer notation, but without modifying the last approach. So I'll simply introduce new symbols for the operations defined above, using some of the operator symbols that Mathematica knows in terms of their operator precedence, but has no pre-defined meanings for:
CirclePlus ⊕ typed as escc+esc
CircleDot ⊙ typed as escc.esc
CircleTimes ⊗ typed as escc*esc
I'll use them as follows:
CirclePlus[ops__] := addOps[ops];
CircleDot[scalar_, op_] := multiplyOp[scalar, op];
CircleTimes[ops__] := Composition[ops];
With this, we can now use Infix notation to write in a more "natural" fashion:
(dx ⊕ dy ⊕ z⊙Identity)@(x ψ[x,y])
$x \psi ^{(0,1)}(x,y)+x \psi ^{(1,0)}(x,y)+\psi (x,y)+x z \psi (x,y)$
As the third operator, CircleTimes ⊗, I've also defined the composition of operators. That allows us to do things like commutators:
commutator = dx ⊗ x⊙Identity ⊕ (-x)⊙Identity ⊗ dx;
I'm relying on the fact that ⊙ has higher precedence than ⊗ which in turn has higher precedence than ⊕ (according to the documentation).
As expected, the commutator is unity, as we can check by applying to a test function:
commutator@f[x]
f[x]